from typing import Annotated
from langchain_core.runnables import RunnableConfig
from langchain_core.tools import InjectedToolArg
from langgraph.store.base import BaseStore
from langgraph.prebuilt import InjectedState, InjectedStore
# 可以是同步或异步;不需要 @tool 装饰器
async def my_tool(
# 这些参数由 LLM 填充
some_arg: str,
another_arg: float,
# config: RunnableConfig 在 LangChain 调用中始终可用
# 这不会暴露给 LLM
config: RunnableConfig,
# 以下三个是特定于预构建的 ToolNode
# (以及 `create_react_agent` 扩展)。如果你在自己的节点中单独调用工具,
# 那么你需要自己提供这些。
store: Annotated[BaseStore, InjectedStore],
# 这会传递完整的状态。
state: Annotated[State, InjectedState],
# 你也可以从状态中注入单个字段
messages: Annotated[list, InjectedState("messages")]
# 以下与 create_react_agent 或 ToolNode 不兼容
# 你也可以排除其他不向模型显示的参数。
# 这些必须手动提供,如果你在自己的节点中调用工具/函数,它们会很有用
# some_other_arg=Annotated["MyPrivateClass", InjectedToolArg],
):
"""调用 my_tool 对现实世界产生影响。
参数:
some_arg: 一个非常重要的参数
another_arg: LLM 将提供的另一个参数
"""
# 文档字符串成为工具的描述并传递给模型
print(some_arg, another_arg, config, store, state, messages)
# Config, some_other_arg, store 和 state 在传递给 bind_tools 或 with_structured_output 时
# 对 LangChain 模型是“隐藏”的
return "... some response"
from typing import List
# this is the state schema used by the prebuilt create_react_agent we'll be using below
from langgraph.prebuilt.chat_agent_executor import AgentState
from langchain_core.documents import Document
class State(AgentState):
docs: List[str]
from typing import List, Tuple
from typing_extensions import Annotated
from langchain_core.messages import ToolMessage
from langchain_core.tools import tool
from langgraph.prebuilt import InjectedState
@tool
def get_context(question: str, state: Annotated[dict, InjectedState]):
"""Get relevant context for answering the question."""
return "\n\n".join(doc for doc in state["docs"])
print(get_context.get_input_schema().model_json_schema())
{'description': 'Get relevant context for answering the question.',
'properties':
{'question': {'title': 'Question', 'type': 'string'},
'state': {'title': 'State', 'type': 'object'}},
'required': ['question', 'state'],
'title': 'get_context', 'type': 'object'}
但是如果我们看一下tool-call schema(即传递给模型进行工具调用的内容),状态已被删除,因为我们不希望llm看到需要填充这些参数:
print(get_context.tool_call_schema.model_json_schema())
{'description': 'Get relevant context for answering the question.',
'properties': {
'question': {'title': 'Question', 'type': 'string'}},
'required': ['question'],
'title': 'get_context', 'type': 'object'}
from langchain_ollama import ChatOllama
import base_conf
from langgraph.prebuilt import ToolNode, create_react_agent
from langgraph.checkpoint.memory import MemorySaver
model = ChatOllama(base_url=base_conf.base_url,model=base_conf.model_name,temperature=0)
tools = [get_context]
# ToolNode 将自动负责将state注入tool
tool_node = ToolNode(tools)
checkpointer = MemorySaver()
graph = create_react_agent(model, tools, state_schema=State, checkpointer=checkpointer)
docs = [
"FooBar company just raised 1 Billion dollars!",
"FooBar company was founded in 2019",
]
inputs = {
"messages": [{"type": "user", "content": "what's the latest news about FooBar"}],
"docs": docs,
}
config = {"configurable": {"thread_id": "1"}}
for chunk in graph.stream(inputs, config, stream_mode="values"):
chunk["messages"][-1].pretty_print()
================================ Human Message =================================
what's the latest news about FooBar
================================== Ai Message ==================================
Tool Calls:
get_context (e1eeaa88-b5f4-45ae-abf3-ed7fd861ce66)
Call ID: e1eeaa88-b5f4-45ae-abf3-ed7fd861ce66
Args:
question: latest news about FooBar
================================= Tool Message =================================
Name: get_context
FooBar company just raised 1 Billion dollars!
FooBar company was founded in 2019
================================== Ai Message ==================================
The latest news about FooBar is that the company has just raised 1 Billion dollars! For reference, FooBar was founded in 2019.
from langgraph.store.memory import InMemoryStore
doc_store = InMemoryStore()
namespace = ("documents", "1")
doc_store.put(
namespace, "doc_0", {"doc": "FooBar company just raised 1 Billion dollars!"}
)
namespace = ("documents", "2") # user ID
doc_store.put(namespace, "doc_1", {"doc": "FooBar company was founded in 2019"})
from langgraph.store.base import BaseStore
from langchain_core.runnables import RunnableConfig
from langgraph.prebuilt import InjectedStore
@tool
def get_context(
question: str,
config: RunnableConfig,
store: Annotated[BaseStore, InjectedStore()],
) -> Tuple[str, List[Document]]:
"""Get relevant context for answering the question."""
user_id = config.get("configurable", {}).get("user_id")
docs = [item.value["doc"] for item in store.search(("documents", user_id))]
return "\n\n".join(doc for doc in docs)
print(get_context.tool_call_schema.model_json_schema())
{'description': 'Get relevant context for answering the question.',
'properties': {'question':
{'title': 'Question', 'type': 'string'}},
'required': ['question'], 'title': 'get_context', 'type': 'object'}
tools = [get_context]
# ToolNode 会自动把 Store 注入到 tools
tool_node = ToolNode(tools)
checkpointer = MemorySaver()
graph = create_react_agent(model, tools, checkpointer=checkpointer, store=doc_store)
messages = [{"type": "user", "content": "what's the latest news about FooBar"}]
config = {"configurable": {"thread_id": "1", "user_id": "1"}}
for chunk in graph.stream({"messages": messages}, config, stream_mode="values"):
chunk["messages"][-1].pretty_print()
================================ Human Message =================================
what's the latest news about FooBar
================================== Ai Message ==================================
Tool Calls:
get_context (89b2d78c-6b6d-4c46-a5a7-cee513bff5cb)
Call ID: 89b2d78c-6b6d-4c46-a5a7-cee513bff5cb
Args:
question: latest news about FooBar
================================= Tool Message =================================
Name: get_context
FooBar company just raised 1 Billion dollars!
================================== Ai Message ==================================
The latest news is that FooBar company has just raised 1 Billion dollars!
messages = [{"type": "user", "content": "what's the latest news about FooBar"}]
config = {"configurable": {"thread_id": "2", "user_id": "2"}}
for chunk in graph.stream({"messages": messages}, config, stream_mode="values"):
chunk["messages"][-1].pretty_print()
================================ Human Message =================================
what's the latest news about FooBar
================================== Ai Message ==================================
Tool Calls:
get_context (817da555-c13e-4fa1-8bbe-3854713fc643)
Call ID: 817da555-c13e-4fa1-8bbe-3854713fc643
Args:
question: latest news about FooBar
================================= Tool Message =================================
Name: get_context
FooBar company was founded in 2019
================================== Ai Message ==================================
The information I have currently states that FooBar company was founded in 2019. However, this doesn't provide the latest news. Could you please specify a date range or give me some more time to fetch the most recent updates?