用Python+LangChain构建PDF术语库:实体抽取+Embedding+向量检索全流程 前言做 PDF 翻译的朋友都懂一个痛同一份 80 页文档同一个专业术语前后译法不一致。这个问题单靠翻译引擎很难根治行业里普遍的做法是引入术语库Terminology Base——翻译前先把术语锁定引擎不可随意改写。但人工建术语库费时费力。本文分享一套自动化方案用 Python LangChain 从历史语料里自动抽取专业术语、做 Embedding 入库、再提供向量检索接口供翻译管线在切句翻译环节实时查询并锁定术语。照着做你也能搭出一个术语一致性兜底引擎。环境准备Python 3.10依赖安装pipinstalllangchain langchain-community langchain-openai openpyxl chromadb sentence-transformers一个可用的 Embedding 模型本地可用sentence-transformers/all-MiniLM-L6-v2无需联网一份历史双语语料源语言 目标语言对齐的句子对这里用英文合同为例实现步骤整体管线分四步实体抽取 → 术语归一化 → Embedding 入库 → 向量检索。Step 1: 用 LLM 抽取领域实体先用 LangChain 的ChatOpenAI或本地模型跑一个结构化抽取把源语料里属于专业术语的实体识别出来并给出建议译文。为控制成本抽取可以只在首次建库时执行一次。fromlangchain_openaiimportChatOpenAIfromlangchain_core.output_parsersimportJsonOutputParserfromlangchain_core.promptsimportPromptTemplate llmChatOpenAI(modelgpt-4o-mini,temperature0)promptPromptTemplate.from_template(你是资深法律/技术术语标注员。从下面的英文句子中抽取专业术语并给出规范中文译文。 只输出 JSON 数组每项含 source(英文原词)、target(建议中文译文)、category(术语分类)。 句子: {sentence} )parserJsonOutputParser()chainprompt|llm|parserdefextract_terms(sentence:str)-list:抽取单句中的专业术语returnchain.invoke({sentence:sentence})# 示例termsextract_terms(The Seller shall indemnify the Buyer against any loss arising from breach of warranty.)print(terms)# [{source: indemnify, target: 赔偿, category: 法律},# {source: breach of warranty, target: 违反保证, category: 法律}]Step 2: 术语归一化与去重同一实体可能有不同写法单复数、时态、大小写。用词形还原 小写统一并聚合同源术语的译文投票保证术语库干净。importrefromcollectionsimportdefaultdictdefnormalize_term(term:str)-str:归一化小写、去空白、简单词形还原tterm.strip().lower()# 去掉冠词tre.sub(r^(the|a|an)\s,,t)returntdefmerge_terms(term_list:list)-list:合并同源术语译文取出现次数最多的groupsdefaultdict(list)foriteminterm_list:groups[normalize_term(item[source])].append(item)merged[]forsrc,itemsingroups.items():# 取最常见的译文targetmax(set(i[target]foriinitems),keylambdax:sum(1foriinitemsifi[target]x))merged.append({source:src,target:target,category:items[0][category]})returnmergedStep 3: Embedding 向量化入库把术语库写入 Chroma 向量库这样翻译时可以用语义相似来匹配变体表达如 “Seller shall indemnify” 与 “indemnify the Buyer” 都能命中 “indemnify”。importchromadbfromchromadb.utilsimportembedding_functions# 本地 sentence-transformers 嵌入efembedding_functions.SentenceTransformerEmbeddingFunction(model_namesentence-transformers/all-MiniLM-L6-v2)clientchromadb.PersistentClient(path./term_db)collectionclient.get_or_create_collection(pdf_terms,embedding_functionef)defbuild_term_db(terms:list)-None:将术语列表向量化写入 Chromaifnotterms:returnids[fterm_{i}foriinrange(len(terms))]documents[t[source]fortinterms]metadatas[{target:t[target],category:t[category]}fortinterms]collection.upsert(idsids,documentsdocuments,metadatasmetadatas)print(f已入库{len(terms)}条术语)# 假设 merged_terms 来自 Step 2# build_term_db(merged_terms)Step 4: 翻译前的术语检索与锁定翻译某段文本前先把该段与术语库做向量相似度检索命中高分的术语塞进翻译 prompt 的约束项强制引擎保持一致的译文。deflock_terms_for_sentence(sentence:str,top_k:int3)-str:检索命中的术语生成翻译约束描述hitscollection.query(query_texts[sentence],n_resultstop_k)ifnothits[documents]:return无constraints[]fordoc,metainzip(hits[documents][0],hits[metadatas][0]):constraints.append(f{doc}→{meta[target]})return; .join(constraints)deftranslate_with_term_lock(sentence:str)-str:带术语约束的翻译constraintlock_terms_for_sentence(sentence)prompt_tf翻译下面英文为中文。以下术语必须按下表译文翻译不得改写 术语约束:{constraint}原文:{sentence}译文:# 调用翻译 LLM / APIrespllm.invoke(prompt_t)returnresp.content完整代码整合四个步骤的可运行脚本核心骨架可按需扩展接入任意翻译 API# term_db_builder.pyimportrefromcollectionsimportdefaultdictimportchromadbfromchromadb.utilsimportembedding_functions efembedding_functions.SentenceTransformerEmbeddingFunction(model_namesentence-transformers/all-MiniLM-L6-v2)clientchromadb.PersistentClient(path./term_db)collectionclient.get_or_create_collection(pdf_terms,embedding_functionef)defnormalize_term(term:str)-str:tterm.strip().lower()tre.sub(r^(the|a|an)\s,,t)returntdefmerge_terms(term_list:list)-list:groupsdefaultdict(list)foriteminterm_list:groups[normalize_term(item[source])].append(item)merged[]forsrc,itemsingroups.items():targetmax(set(i[target]foriinitems),keylambdax:sum(1foriinitemsifi[target]x))merged.append({source:src,target:target,category:items[0][category]})returnmergeddefbuild(terms:list):termsmerge_terms(terms)ifnotterms:returnids[fterm_{i}foriinrange(len(terms))]collection.upsert(idsids,documents[t[source]fortinterms],metadatas[{target:t[target],category:t[category]}fortinterms])print(f入库{len(terms)}条)defquery(sentence:str,top_k:int3):hitscollection.query(query_texts[sentence],n_resultstop_k)ifnothits[documents]:return[]return[{term:d,**m}ford,minzip(hits[documents][0],hits[metadatas][0])]运行效果以英文合同 “The Seller shall indemnify the Buyer against any loss arising from breach of warranty.” 测试术语约束: indemnify → 赔偿; breach of warranty → 违反保证 译文: 卖方应赔偿买方因违反保证而产生的任何损失。全文多句测试中凡出现 “indemnify” 的句子均被约束为赔偿有效避免前后译法漂移。总结实体抽取解决术语从哪来Embedding 向量检索解决变体如何命中约束注入解决引擎如何服从。建库是一次性成本之后翻译全程复用尤其适合法律、医疗、制造业等术语高度行业化的 PDF。更进一步可把术语库接入企业自有翻译 API如需整页格式保留的在线 PDF 翻译可参考 PDFTranslator 这类内置版式保留的服务它们通常也做了后台术语一致性处理形成自动抽取 建库 约束翻译的完整闭环。标签PDF翻译、LangChain、向量检索、术语库、Python自动化