新增系统环境变量

1.OPENAI_API_KEY # langchain官方发布的兼容openai SDK包的连接工具,使用香港代理

2.TAVILY_API_KEY # 网页在线搜索API

3.LANGSMITH_API_KEY # LangSmith相关,还有LANGSMITH_ENDPOINT、LANGSMITH_TRACING等

使用各家公司官网提供的大模型Web方式的问题进行联网搜索回答也属于RAG,不仅仅是自己写代码处理文档调用LLM问答才是RAG,联网搜索通过精简网页内容,提炼精华回答用户问题也属于RAG!简而言之,只要引入了外部知识库,都可以看成RAG,要有这个概念。

代码相关

动态传参不能在ChatPromptTemplate中使用HumanMessage, SystemMessage的方式进行传递,必须要用元组的方式传参才有效

LangChain 的 ChatPromptTemplate 替换变量的机制是通过 template 字符串或在 from_messages 中使用元组 (role, template_string) 来识别并替换占位符,ChatPromptTemplate 在处理 from_messages 时,会遍历消息列表。提供元组 (role, template_string) 时,template_string 会被视为一个可以包含占位符的模板。ChatPromptTemplate 会在 invoke 方法被调用时,使用传入的变量来替换这些占位符。直接将 '{topic}' 放入 HumanMessagecontent 中时,它被视为一个普通的字符串,而不是一个可替换的模板变量,这意味着 ChatPromptTemplate 不会再对其内部进行变量替换的扫描和处理。它会原封不动地将 '{topic}' 作为普通文本传递下去。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 正确方式
chat_prompt_template = ChatPromptTemplate.from_messages([
('system', 'You are a useful assitang'),
('human', '以JSON格式输出中国、美国、日本的{topic}')
], template_format='f-string')

result_2 = chat_prompt_template.invoke({'topic': '人口'})
pprint.pprint(result_2)

# 输出
ChatPromptValue(messages=[SystemMessage(content='You are a useful assitang', additional_kwargs={}, response_metadata={}), HumanMessage(content='以JSON格式输出中国、美国、日本的人口', additional_kwargs={}, response_metadata={})])
-----------------------------------------------------------------------------------------
-----------------------------------------------------------------------------------------
# 错误方式
chat_prompt_template = ChatPromptTemplate.from_messages([

('system', 'You are a useful assitang'),

HumanMessage(content='以JSON格式输出中国、美国、日本的{topic}')

], template_format='f-string')
result_2 = chat_prompt_template.invoke({'topic': '人口'})
pprint.pprint(result_2) #报错

f-string,格式化字符串问题

以下类似的代码会导致完全不同的结果输出,主要原因在于f-stringLangChain 的模板引擎会在调用 prompt.invoke({'input': '...'}) 时,查找 input 这个键,并将其对应的值替换到 {input} 这个占位符的位置。这也是 LangChain 期望的默认行为,是实现模板化提示的正确方式。如果将 suffix=f'问题:{input}' 传递给 LangChain, 接收到的将是一个已经完全格式化好的普通字符串,而不是一个带有 {input} 占位符的模板。这意味着 LangChain 的模板引擎将无法在后续的 invoke({'input': '...'}) 调用中对 input 进行替换,因为字符串中已经没有可供替换的 {input} 了,传入的 {'input': '...'} 字典将变得毫无意义,因为它找不到匹配的占位符。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 正确写法
prompt = FewShotPromptTemplate(
examples = examples,
example_prompt = example_prompt,
suffix='问题:{input}',
)
print(prompt.invoke({'input':'乔治·华盛顿的父亲是谁?'}).to_string())
# 问题:乔治·华盛顿的父亲是谁?
-----------------------------------------------------------------------------------------
# 错误写法
prompt = FewShotPromptTemplate(
examples = examples,
example_prompt = example_prompt,
suffix=f'问题:{input}',
)
print(prompt.invoke({'input':'乔治·华盛顿的父亲是谁?'}).to_string())
# 问题:<built-in function input>

LangChain的 Runnable接口

参考文章:【LangChain】什么是 Runnable

在 LangChain 中,Runnable 是一个核心概念(接口),指的是可以被执行(“run”)的对象,通常用于构建和组合工作流。Runnable 是 LangChain Expression Language(LCEL)的基石,允许开发者通过声明式的方式将提示(Prompt)、语言模型(LLM)、解析器(Output Parser)等组件组合成链(Chain),并以统一的方式调用。

什么是Runnable

官网概念描述

Runnable 是 LangChain 中定义在 langchain_core.runnables 模块中的抽象接口,代表一个可执行的单元,很多 LangChain 的组件都实现了这个接口,如 ChatModel、LLMs、OutputParser、Retriever、Prompt 等。任何实现 Runnable 接口的对象都可以通过标准方法(如 invokestreambatch)运行,处理输入并生成输出,Runnable 返回的是它处理后的输出,具体取决于 Runnable 的类型和定义的任务。输出可以是任何 Python 对象Runnable 的设计目标是:

  1. 统一接口:为不同组件(如 LLM、提示模板、解析器)提供一致的调用方式,例如都能用invoke()
  2. 模块化组合:通过 LCEL(如 | 运算符)将多个 Runnable 组合成复杂工作流。
  3. 灵活性:支持同步、异步、流式和批量调用,适配各种场景。
  4. 组件抽象:将复杂功能(LLM 调用、提示生成、数据检索)封装为可复用的模块。
  5. 支持自定义 Runnable,允许开发者实现特定逻辑。
  6. 动态处理:支持条件分支(RunnableBranch)、并行执行(RunnableParallel)等高级功能。

组件输入输出类型

组件 输入类型 输出类型
Prompt python format 格式的字符串 PromptValue
ChatModel String、ChatMessage、PromptValue ChatMessage
LLM String、ChatMessage、PromptValue String
OutputParser String、ChatMessage 依赖 parser 的解析规则
Retriever String Documents
Tool String、dictionary 依赖 tool 的规则

Runnable接口定义了很多同步和异步的方法来保证 chain 的生成,核心方法包括下面几个

  • invoke(input):同步调用,处理单个输入,返回输出。
  • ainvoke(input):异步调用,适合高并发场景。
  • stream(input):流式调用,逐步返回输出(例如逐字生成)。
  • batch(inputs):使用一个数组的输入去调用链,批量调用,处理多个输入。
  • abatch(inputs):异步批量调用。

Runnable 主要类型

再强调一遍,Runnable 返回的是它处理后的输出,具体取决于 Runnable 的类型和定义的任务。输出可以是任何 Python 对象

  • RunnableSequence:按顺序执行多个 Runnable,前一个的输出作为后一个的输入。通过 | 运算符创建(如 prompt | llm | parser)。

  • RunnableParallel:并行执行多个Runnable,将结果组合为字典,结果以字典形式返回。

  • RunnablePassthrough:直接传递输入,常用作占位符或保持输入不变,常用于在并行链中传递原始问题。

1
chain = {"question": RunnablePassthrough()} | prompt
  • RunnableLambda:将任意Python函数封装为Runnable,方便自定义逻辑。。

  • RunnableBranch:根据条件动态选择执行不同的Runnable分支。

  • RunnableWithMessageHistory:管理对话历史,适用于多轮对话链。

  • RunnableMap:对输入的集合中的每个元素应用同一个Runnable,类似于map操作。

  • RunnableFilter:根据条件过滤输入数据。

  • RunnableReduce:对输入集合执行归约操作。

  • RunnableRetry:在失败时重试执行Runnable。

  • RunnableCache:对Runnable的结果进行缓存,避免重复计算。

  • RunnableTransform:对输入或输出进行转换处理。

  • RunnableConditional:根据输入条件执行不同的Runnable。

  • RunnableParallelForEach:并行地对输入列表中的每个元素执行Runnable。

  • RunnableErrorHandler:捕获并处理执行中的异常。

  • 内置组件Runnable

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
from langchain_core.runnables import RunnableLambda, RunnableParallel, RunnablePassthrough, RunnableSequence, RunnableBranch, RunnableWithMessageHistory
from langchain_core.messages import ChatMessageHistory
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser

# RunnableSequence: 按顺序执行,如先加1再乘2
add_one = RunnableLambda(lambda x: x + 1)
double = RunnableLambda(lambda x: x * 2)
sequence = add_one | double
print(sequence.invoke(5)) # 输出: 12

# RunnableParallel: 并行执行,如都加1和乘2
parallel = RunnableParallel({"add": add_one, "double": double})
print(parallel.invoke(5)) # 输出: {"add": 6, "double": 10}

# RunnablePassthrough: 直接传递输入
passthrough = RunnablePassthrough()
print(passthrough.invoke("hello")) # 输出: hello

# RunnableLambda: 自定义逻辑,如转换为大写
uppercase = RunnableLambda(lambda x: x.upper())
print(uppercase.invoke("hello")) # 输出: HELLO

# RunnableBranch: 根据条件选择分支
branch = RunnableBranch(
(lambda x: x > 0, RunnableLambda(lambda x: x * 2)), # 正数乘2
(lambda x: x <= 0, RunnableLambda(lambda x: x * -1)), # 非正数取反
RunnableLambda(lambda x: x) # 默认
)
print(branch.invoke(5)) # 输出: 10

# RunnableWithMessageHistory: 管理对话历史
store = {}
def get_history(input_tuple):
user_id, conv_id = input_tuple
if (user_id, conv_id) not in store:
store[(user_id, conv_id)] = ChatMessageHistory()
return store[(user_id, conv_id)] # 返回 ChatMessageHistory 实例

history_runnable = RunnableWithMessageHistory(
RunnableLambda(lambda x: f"Received: {x}"),
get_session_history=get_history,
input_messages_key="input",
history_messages_key="history"
)
print(history_runnable.invoke(
{"input": "Hi", "user_id": 101, "conv_id": "chat1"},
config={"configurable": {"session_id": (101, "chat1")}}
)) # 输出: Received: Hi

# 内置组件示例:结合提示模板和字符串解析器(模拟语言模型)
uppercase = RunnableLambda(lambda x: x.messages[0].content.upper())
prompt = ChatPromptTemplate.from_template(template="Say {word} in uppercase")
parser = StrOutputParser()
builtin_chain = prompt | uppercase | parser
print(builtin_chain.invoke({"word": "hello"})) # 输出: SAY HELLO IN UPPERCASE

output_parsers相关

Output Parsers的主要作用是定义如何将大语言模型(LLM)的原始输出解析、转换为结构化的、有意义的 Python 数据结构,方便后续程序处理,它规定了“如何把 LLM 生成的内容变成代码能直接用的数据”。

LangChain提供了多种输出解析器,包括json、xml、list以及其他多种格式。实际背后是通过动态插入值到提示词模版中实现的,本质还是利用了提示词工程技术。初始在定义prompt时把要想要的输出的格式跟大模型说明,langchain在代码底层提供了针对各种输出格式的提示词模版,还利用了少样本提示方法(Few-Shot),现在的大模型都有很好的指令执行能力,能够较好地理解用户想要的输出格式,进而能输出符合预期格式的内容。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# json格式提示词模版
"""Format instructions."""

JSON_FORMAT_INSTRUCTIONS = """The output should be formatted as a JSON instance that conforms to the JSON schema below.

As an example, for the schema {{"properties": {{"foo": {{"title": "Foo", "description": "a list of strings", "type": "array", "items": {{"type": "string"}}}}}}, "required": ["foo"]}}
the object {{"foo": ["bar", "baz"]}} is a well-formatted instance of the schema. The object {{"properties": {{"foo": ["bar", "baz"]}}}} is not well-formatted.

Here is the output schema:
```
{schema}
```"""
###########################################################################################################
# XML提示词模版
XML_FORMAT_INSTRUCTIONS = """The output should be formatted as a XML file.
1. Output should conform to the tags below.
2. If tags are not given, make them on your own.
3. Remember to always open and close all the tags.

As an example, for the tags ["foo", "bar", "baz"]:
1. String "<foo>\n <bar>\n <baz></baz>\n </bar>\n</foo>" is a well-formatted instance of the schema.
2. String "<foo>\n <bar>\n </foo>" is a badly-formatted instance.
3. String "<foo>\n <tag>\n </tag>\n</foo>" is a badly-formatted instance.

Here are the output tags:
```
{tags}
```""" # noqa: E501
###########################################################################################################
# list提示词模版
def get_format_instructions(self) -> str:
"""Return the format instructions for the comma-separated list output."""
return (
"Your response should be a list of comma separated values, "
"eg: `foo, bar, baz` or `foo,bar,baz`"
)

XMLOutputParser为例,format_instruction就是针对不同格式针对特定任务动态插入的提示词,只是在已有提示词模版最后中加入一句针对特定任务的描述,例如:

Here is the output schema:

{"properties": {"setup": {"title": "Setup", "type": "string"}, "punchline": {"description": " 解决笑话的答案", "title": "Punchline", "type": "string"}}, "required": ["punchline"]}

1
2
Here is the output schema:
{"properties": {"setup": {"title": "Setup", "type": "string"}, "punchline": {"description": " 解决笑话的答案", "title": "Punchline", "type": "string"}}, "required": ["punchline"]}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
from langchain_core.prompts import PromptTemplate
from langchain_core.output_parsers.xml import XMLOutputParser
from LLM import model

actor_query = '生成十部周星驰的电影作品列表,按最新的时间降序,中文'

parser = XMLOutputParser(tags=['周星驰电影作品列表','电影名称','上映时间','主演'])
prompt = PromptTemplate(
template = '回答用户的问题。\n{format_instruction}\n{query}\n',
input_variables = ['query'],
partial_variables = {'format_instruction':parser.get_format_instructions()} # 调用get_format_instructions方法获取针对特定任务的提示词
)

chain = prompt | model
response = chain.invoke({'query':actor_query})
print(response.content)

# 输出
```xml
<周星驰电影作品列表>
<电影名称>美人鱼</电影名称>
<上映时间>2016年2月8日</上映时间>
<主演>周星驰, 林允, 杜鹃</主演>
</周星驰电影作品列表>
<周星驰电影作品列表>
<电影名称>西游降魔篇</电影名称>
<上映时间>2013年2月10日</上映时间>
<主演>周星驰, 文章, 饶雪漫</主演>
</周星驰电影作品列表>
<周星驰电影作品列表>
<电影名称>大话西游之大圣娶亲</电影名称>
<上映时间>1995年5月13日</上映时间>
<主演>周星驰, 莫文蔚, 吴孟达</主演>
</周星驰电影作品列表>
...
```

json格式的get_format_instructions()具体实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
def get_format_instructions(self) -> str:
"""Return the format instructions for the JSON output.

Returns:
The format instructions for the JSON output.
"""
if self.pydantic_object is None:
return "Return a JSON object."
# Copy schema to avoid altering original Pydantic schema.
schema = dict(self._get_schema(self.pydantic_object).items())

# Remove extraneous fields.
reduced_schema = schema
if "title" in reduced_schema:
del reduced_schema["title"]
if "type" in reduced_schema:
del reduced_schema["type"]
# Ensure json in context is well-formed with double quotes.
schema_str = json.dumps(reduced_schema, ensure_ascii=False)
return JSON_FORMAT_INSTRUCTIONS.format(schema=schema_str)

动态转换提示词模版

Agent

LLM本身无法采取行动,它们只能输出文本。LangChain的一个重要用例是创建Agent。Agent是使用LLM作为推理引擎的指挥系统,用于确定应采取哪些行动以及这些行动的输入应该是什么。然后将这些行动的结果反馈给LLM,并确定是否需要更多行动,或者是否可以结束。LangChain代理适合入门,在一定程度之后,如果希望拥有LangChain无法提供的灵活性和控制性,需要使用更高级的代理,建议查看LangGraph。

使用langchain第三方Agent工具包构建智能体时(例如langchain_community.agent_toolkits),大部分都是通过底层预设值的提示词实现的,并没有使用多高级的技术。可以通过langsmith链路查看agent的每一步实现细节。

官方提供的一个提示词仓库,包含各种提示词:https://smith.langchain.com/hub,下面用到的提示词也是出自hub的`langchain-ai/sql-agent-system-prompt`

langsmith追踪agent运行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

from langchain_community.utilities import SQLDatabase
from langchain.chat_models import ChatOpenAI
from langchain.agents import initialize_agent, Tool
from langchain_community.agent_toolkits.sql.toolkit import SQLDatabaseToolkit
from Pythonic.demo1.model.LLM import model

# 连接 MySQL 数据库
db = SQLDatabase.from_uri('mysql+pymysql://root:root@localhost:3306/sakila')


# 创建 SQLDatabaseToolkit,传入数据库和 LLM
toolkit = SQLDatabaseToolkit(db=db, llm=model)

# 获取工具列表
tools = toolkit.get_tools()

# 创建 agent,使用 AgentExecutor(Legacy)
agent = initialize_agent(
tools,
model,
agent="zero-shot-react-description", # 经典 ReAct agent
verbose=True, # 打印详细日志
)

# 通过 agent 提问数据库
question = "数据库一共有哪些表?每个表的作用是什么?使用中文回答问题。"

result = agent.run(question)

print("回答:", result)

agent也可以实现记忆相关的内容,可以给它添加记忆相关的组件,例如:

1
2
3
4
5
6
7
8
response = agent_executor.invoke(
'chat_history':[
HumanMessage(contentt='你好,我是的名字是L'),
AIMessage(content='你好,L,很高兴见到你!请问有什么我可以帮助你的吗?')
],
'input':'我的名字是什么?'
)
print(response)

embedding

使用嵌入模型(embedding)时,模型为输入的每个词或token生成一个固定维度的嵌入向量。例如OpenAI的text-embedding-ada-002模型会为每个token生成1536维的向量。然后通过某种聚合方式(如平均池化、取[CLS] token或其他方法)将每个token的嵌入向量合并,得到整句话的向量化表达,最终输出的向量(如1536维)是代表整句话的向量化表达,而不是单个词的向量。输出向量是句子的整体嵌入,表示整个序列的语义。

RecursiveCharacterTextSplitter和CharacterTextSplitter切分方式有什么不同?


CharacterTextSplitter:简单地按固定字符数(chunk_size)切分文本,通常是从头开始按字符数切割成若干块。

  • 直接按长度切分,不考虑文本结构或语义

  • 切分点可能在句子或单词中间,导致语义断裂。

  • 实现简单,速度快。

  • 适用于对文本结构要求不高,或者只需快速切分的场景。


RecursiveCharacterTextSplitter:递归地尝试按一系列分隔符(默认是 ["\n\n", "\n", " ", ""])从大到小切分文本,优先保持语义完整的段落或句子。

  • 先尝试按段落(双换行)切分,如果块太大,再按换行、空格等更细粒度切分。

  • 递归切分,尽量避免在语义强相关的文本中间断开。

  • 支持自定义分隔符列表,适应不同语言和文本格式。

  • 适用于需要保持文本语义连贯,适合自然语言处理任务。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from langchain_chroma import Chroma
from langchain_community.document_loaders import TextLoader
from langchain_text_splitters import CharacterTextSplitter
from Pythonic.demo1.model.LLM import model
from Pythonic.demo1.model.EmbeddingModel import embedding_model
from langchain.text_splitter import RecursiveCharacterTextSplitter

# 加载文档并将其分割成片段
loader = TextLoader("qa.txt", encoding="UTF-8")
documents = loader.load()
# 将其分割成片段
text_splitter = RecursiveCharacterTextSplitter(chunk_size=20, chunk_overlap=0)
docs = text_splitter.split_documents(documents)
print(docs)

# 将其加载到 Chroma 内存中
db = Chroma.from_documents(docs, embedding_model)
# 进行查询
query = "第一督导组副组长是谁?"
docs = db.similarity_search(query,k=1)
# 打印结果
print(docs[0].page_content)

chroma数据库向量化问题

Collection 和 Segment

Collection 是 Chroma 中的高级抽象,类似于传统数据库中的表。它是相关数据的逻辑集合,包含文档/数据、这些文档的向量嵌入、可选的元数据等内容。

Segment 是 Collection 内部的底层存储单元。一个 Collection 通常由多个 Segment 组成,这种设计使得 Chroma 能够并行处理查询、分散存储负载并提高整体性能。

区别:Collection 是面向用户的逻辑单元,而 Segment 是内部实现细节,用于实际存储数据并处理查询。

chroma数据库向量化后的vector存储在embeddings_queue表中,vector字段中的长字符是十六进制编码后的向量数据,这是一种常见的数据存储和传输方式,特别是在数据库中。向量通常由一组浮点数( float32float64)组成。 可能是 [0.123, -0.456, 0.789, ...]。在数据库中,直接存储浮点数数组可能会比较复杂,尤其是在没有原生向量数据类型的数据库中(如 SQLite)。 因此,一种常见的做法是将浮点数数组序列化(serialize)成一个字节流(byte stream)。将这个字节流编码成一个可读的字符串格式,最常见的就是十六进制(Hex)编码。下面的向量是由 float32 类型组成的(一个 float32 占用 4 个字节),那么这个十六进制字符串中的每 8 个字符就代表一个浮点数。 如果将这个十六进制字符串解码回字节流,然后再将字节流解释为一组 float32 浮点数,你就可以得到原始的向量。在 Python 代码中,当你从数据库中读取这个值时,Chroma 库会负责自动将其解码回原始的浮点数向量,这样你就可以直接使用它进行相似性搜索、计算距离等操作了。

chroma数据库存储向量形式

RAG检索的两种匹配方式

  1. 欧氏距离
  2. 余弦相似度

RAG

LLM预训练数据集之外的新数据称为外部数据。它可以来自多个数据来源,例如API、数据库或文档存储库。数据可能以各种格式存在,例如文件、数据库记录或长篇文本。另一种称为嵌入语言模型的AI技术将数据转换为数字表示形式并将其存储在向量数据库中。这个过程会创建一个生成式人工智能模型可以理解的知识库。

下一步是执行相关性搜索。用户查询将转换为向量表示形式,并与向量数据库匹配。例如,考虑一个可以回答组织的人力资源问题的智能聊天机器人。如果员工搜索:“我有多少年假?”,系统将检索年假政策文件以及员工个人过去的休假记录。这些特定文件将被退回,因为它们与员工输入的内容高度相关。相关性是使用数学向量计算和表示法计算和建立的。

接下来,RAG模型通过在上下文中添加检索到的相关数据来增强用户输入(或提示)。此步骤使用提示工
程技术与LLM进行有效沟通。增强提示允许大型语言模型为用户查询生成准确的答案。

LangGraph中管理短期记忆的方法

短期记忆通常是比较紧张的,所以需要定期做清理,防止历史消息过多。LangGraph的Agent中,提供了一个pre_model_hook属性,可以在每次调用大模型之前触发。通过这个hook,就可以来定期管理短期记忆。

主要有两种:

  • Summarization总结:用大模型的方式,对短期记忆进行总结,然后再把总结的结果作为新的短期记忆。
  • Trimming 删除:直接把短期记忆中最旧的消息删除掉。

AgentLangGraph后续构建Graph图的基础。但其实Agent并不是LangGraph框架当中独有的。甚至Agent并不是一种技术,而是我们设想的一种理想的大模型工作模式,通过Agent,我们不再需要关注应用的实现细节,而是可以更专注于应用的功能设计。那么到底什么是Agent?理想的Agent应该是什么样子呢?LangGraph使用Graph图的方式协调管理多个Agent,或许是更大的价值所在。

  • 使用LangGraph构建Agent智能体
  • Agent智能体增加Tools工具调用机制
  • Agent智能体消息记忆管理功能
  • Human-In-Loop人类监督功能

LangGraph接入MCP

安装MCP工具要求Python版本>=3.10,否则会报错

LangGraph代理可以通过langchain-mcp-adapters库使用定义在MCP服务器上的工具。要在LangGraph中使用MCP工具,需要安装langchain-mcp-adapters库,安装命令为:

1
2
3
4
5
pip install langchain-mcp-adapters

# Python版本不符合时的报错信息
ERROR: Ignored the following versions that require a different python version: 0.0.1 Requires-Python >=3.11; 0.0.10 Requires-Python >=3.10; 0.0.11 Requires-Python >=3.10; 0.0.2 Requires-Python >=3.11; 0.0.3 Requires-Python >=3.10; 0.0.4 Requires-Python >=3.10; 0.0.5 Requires-Python >=3.10; 0.0.6 Requires-Python >=3.10; 0.0.7 Requires-Python >=3.10; 0.0.8 Requires-Python >=3.10; 0.0.9 Requires-Python >=3.10; 0.1.0 Requires-Python >=3.10; 0.1.1 Requires-Python >=3.10; 0.1.2 Requires-Python >=3.10; 0.1.3 Requires-Python >=3.10; 0.1.4 Requires-Python >=3.10; 0.1.6 Requires-Python >=3.10; 0.1.7 Requires-Python >=3.10; 0.1.8 Requires-Python >=3.10; 0.1.9 Requires-Python >=3.10
ERROR: Could not find a version that satisfies the requirement langchain-mcp-adapters (from versions: none)