v0.0.10
tools
This commit is contained in:
parent
f1cdf6dd1f
commit
eb82b1a174
2
.env
2
.env
@ -3,9 +3,11 @@
|
|||||||
SILICONFLOW_API_KEY = "sk-sylilrjrtxlvecwhfusjkutclmppzuzhncfcfxtekxrzyjee"
|
SILICONFLOW_API_KEY = "sk-sylilrjrtxlvecwhfusjkutclmppzuzhncfcfxtekxrzyjee"
|
||||||
SILICONFLOW_BASE_URL = "https://api.siliconflow.cn/v1"
|
SILICONFLOW_BASE_URL = "https://api.siliconflow.cn/v1"
|
||||||
|
|
||||||
|
# gemma4:e2b
|
||||||
OLLAMA_API_KEY = "ollama"
|
OLLAMA_API_KEY = "ollama"
|
||||||
OLLAMA_BASE_URL = "http://localhost:11434/v1"
|
OLLAMA_BASE_URL = "http://localhost:11434/v1"
|
||||||
|
|
||||||
|
# MiniMax-M2.7
|
||||||
MINIMAX_API_KEY = "sk-cp-wWkzvRP-BiQia-6izxvqgehEsHSz8v4_PtDJAuT3OI0s8QFcEOsxIHcQoZC2cVQTK3L09EUuu5HDArYMvKXFnf91jk8LuZ0tteS7-Wd4Lk2zDm8RqrKkrd4"
|
MINIMAX_API_KEY = "sk-cp-wWkzvRP-BiQia-6izxvqgehEsHSz8v4_PtDJAuT3OI0s8QFcEOsxIHcQoZC2cVQTK3L09EUuu5HDArYMvKXFnf91jk8LuZ0tteS7-Wd4Lk2zDm8RqrKkrd4"
|
||||||
MINIMAX_BASE_URL = "https://api.minimaxi.com/v1"
|
MINIMAX_BASE_URL = "https://api.minimaxi.com/v1"
|
||||||
|
|
||||||
|
|||||||
17
README.md
17
README.md
@ -1,6 +1,6 @@
|
|||||||
# LangChain Learning
|
# LangChain Learning
|
||||||
|
|
||||||
[](https://github.com/your-repo/langchain-learning)
|
[](https://github.com/your-repo/langchain-learning)
|
||||||
[](https://www.python.org/)
|
[](https://www.python.org/)
|
||||||
[](https://www.langchain.com/)
|
[](https://www.langchain.com/)
|
||||||
|
|
||||||
@ -13,6 +13,7 @@
|
|||||||
- **流式响应**:实时流式输出,带来更好的使用体验
|
- **流式响应**:实时流式输出,带来更好的使用体验
|
||||||
- **Prompt 工程**:多种 Prompt 模板构建方式
|
- **Prompt 工程**:多种 Prompt 模板构建方式
|
||||||
- **输出解析**:支持 JSON 等格式解析
|
- **输出解析**:支持 JSON 等格式解析
|
||||||
|
- **工具调用 (Tool Calling)**:支持 @tool 装饰器和 StructuredTool 定义工具
|
||||||
- **Token 用量追踪**:轻松监控 API 调用消耗
|
- **Token 用量追踪**:轻松监控 API 调用消耗
|
||||||
- **内存管理**:实现对话历史持久化(ConversationBufferMemory, SummaryMemory)
|
- **内存管理**:实现对话历史持久化(ConversationBufferMemory, SummaryMemory)
|
||||||
- **Rich 终端界面**:支持 Markdown 渲染、多行输入等高级交互
|
- **Rich 终端界面**:支持 Markdown 渲染、多行输入等高级交互
|
||||||
@ -24,7 +25,7 @@
|
|||||||
### 1. 安装依赖
|
### 1. 安装依赖
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pip install langchain>=1.2.15 langchain-community>=0.4.1 langchain-siliconflow>=1.0.0 requests>=2.33.1 rich openai
|
pip install langchain>=1.2.15 langchain-community>=0.4.1 langchain-siliconflow>=1.0.0 requests>=2.33.1 rich openai pydantic
|
||||||
```
|
```
|
||||||
|
|
||||||
### 2. 配置环境变量
|
### 2. 配置环境变量
|
||||||
@ -72,6 +73,13 @@ OLLAMA_API_KEY=ollama
|
|||||||
|------|------|------|
|
|------|------|------|
|
||||||
| 基础 RAG | `python rag/rag_demo.py` | 基于 FAISS 向量库的检索问答系统 |
|
| 基础 RAG | `python rag/rag_demo.py` | 基于 FAISS 向量库的检索问答系统 |
|
||||||
|
|
||||||
|
**工具调用示例**
|
||||||
|
|
||||||
|
| 示例 | 命令 | 说明 |
|
||||||
|
|------|------|------|
|
||||||
|
| 工具定义 | `python tools/tool_definition.py` | 演示 @tool 装饰器和 StructuredTool 定义方式 |
|
||||||
|
| 工具调用 | `python tools/tool_demo.py` | 演示模型如何调用工具并获取结果 |
|
||||||
|
|
||||||
**Token 用量示例**
|
**Token 用量示例**
|
||||||
|
|
||||||
| 示例 | 命令 | 说明 |
|
| 示例 | 命令 | 说明 |
|
||||||
@ -113,6 +121,9 @@ langchain-learning/
|
|||||||
│ └── json_parser_demo.py # JSON 输出解析示例
|
│ └── json_parser_demo.py # JSON 输出解析示例
|
||||||
├── rag/
|
├── rag/
|
||||||
│ └── rag_demo.py # RAG 检索增强生成示例
|
│ └── rag_demo.py # RAG 检索增强生成示例
|
||||||
|
├── tools/
|
||||||
|
│ ├── tool_definition.py # 工具定义方式演示
|
||||||
|
│ └── tool_demo.py # 工具调用完整流程演示
|
||||||
├── token/
|
├── token/
|
||||||
│ └── token_demo.py # Token 用量追踪示例
|
│ └── token_demo.py # Token 用量追踪示例
|
||||||
├── memory/
|
├── memory/
|
||||||
@ -138,6 +149,7 @@ langchain-learning/
|
|||||||
|
|
||||||
**Ollama (本地)**
|
**Ollama (本地)**
|
||||||
- `gemma4:26b`
|
- `gemma4:26b`
|
||||||
|
- `gemma4:e2b`
|
||||||
- `deepseek-v3.1:671b-cloud`
|
- `deepseek-v3.1:671b-cloud`
|
||||||
|
|
||||||
## 技术栈
|
## 技术栈
|
||||||
@ -148,6 +160,7 @@ langchain-learning/
|
|||||||
| LLM 提供商 | SiliconFlow, Ollama |
|
| LLM 提供商 | SiliconFlow, Ollama |
|
||||||
| 向量库 | FAISS |
|
| 向量库 | FAISS |
|
||||||
| 终端美化 | Rich |
|
| 终端美化 | Rich |
|
||||||
|
| 数据验证 | Pydantic |
|
||||||
| 语言 | Python 3.11+ |
|
| 语言 | Python 3.11+ |
|
||||||
|
|
||||||
## 许可证
|
## 许可证
|
||||||
|
|||||||
56
tools/tool_definition.py
Normal file
56
tools/tool_definition.py
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
import sys
|
||||||
|
|
||||||
|
from langchain_core.tools import tool, StructuredTool
|
||||||
|
from pydantic import BaseModel, Field
|
||||||
|
from sqlalchemy import True_
|
||||||
|
|
||||||
|
|
||||||
|
# 定义函数/tool
|
||||||
|
|
||||||
|
## 方式1:使用注解
|
||||||
|
@tool
|
||||||
|
def get_weather1(city: str) -> str:
|
||||||
|
"""查询指定城市的最新天气信息"""
|
||||||
|
# 通过api调用天气网站的接口,得到最新的天气信息
|
||||||
|
return f"{city}当前的温度为18°C"
|
||||||
|
|
||||||
|
|
||||||
|
class FieldInfo(BaseModel):
|
||||||
|
city: str = Field(description="要查询的城市名称")
|
||||||
|
|
||||||
|
## 注解中可以通过传参覆盖原有函数的描述等信息
|
||||||
|
@tool(
|
||||||
|
name_or_callable="get_weather1",
|
||||||
|
args_schema=FieldInfo,
|
||||||
|
description="查询某个城市的天气,并返回温度信息",
|
||||||
|
return_direct=True
|
||||||
|
)
|
||||||
|
def get_weather2(city: str) -> str:
|
||||||
|
"""查询指定城市的最新天气信息"""
|
||||||
|
# 通过api调用天气网站的接口,得到最新的天气信息
|
||||||
|
return f"{city}当前的温度为18°C"
|
||||||
|
|
||||||
|
|
||||||
|
## 方式2:
|
||||||
|
def get_weather3(city: str) -> str:
|
||||||
|
"""查询指定城市的最新天气信息"""
|
||||||
|
# 通过api调用天气网站的接口,得到最新的天气信息
|
||||||
|
return f"{city}当前的温度为18°C"
|
||||||
|
|
||||||
|
get_weather3_tool = StructuredTool.from_function(
|
||||||
|
func=get_weather3,
|
||||||
|
name="get_weather3",
|
||||||
|
args_schema=FieldInfo,
|
||||||
|
description="第三个返回天气的函数"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
# 调用函数,并打印返回结果
|
||||||
|
print(get_weather1("北京"))
|
||||||
|
print(get_weather1("巴黎"))
|
||||||
|
|
||||||
|
print(f"name={get_weather3_tool.name}")
|
||||||
|
print(f"args={get_weather3_tool.args}")
|
||||||
|
print(f"description={get_weather3_tool.description}")
|
||||||
|
print(f"return_direct={get_weather3_tool.return_direct}") # 直接返回:如果为false,就是会将返回值给到大模型,让大模型进一步加工后再返回。如果是true,则直接返回给用户。
|
||||||
98
tools/tool_demo.py
Normal file
98
tools/tool_demo.py
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
import sys
|
||||||
|
|
||||||
|
from langchain_core.messages import HumanMessage, ToolMessage
|
||||||
|
from langchain_core.tools import tool, StructuredTool
|
||||||
|
from pydantic import BaseModel, Field
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from langchain_openai import ChatOpenAI
|
||||||
|
import os
|
||||||
|
import dotenv
|
||||||
|
|
||||||
|
|
||||||
|
# 定义函数/tool
|
||||||
|
|
||||||
|
## 方式1:使用注解
|
||||||
|
class FieldInfo(BaseModel):
|
||||||
|
city: str = Field(description="要查询的城市名称")
|
||||||
|
|
||||||
|
|
||||||
|
## 注解中可以通过传参覆盖原有函数的描述等信息
|
||||||
|
@tool(
|
||||||
|
name_or_callable="get_weather",
|
||||||
|
args_schema=FieldInfo,
|
||||||
|
description="查询某个城市的天气,并返回温度信息",
|
||||||
|
return_direct=True
|
||||||
|
)
|
||||||
|
def get_weather(city: str) -> str:
|
||||||
|
"""查询指定城市的最新天气信息"""
|
||||||
|
# 通过api调用天气网站的接口,得到最新的天气信息
|
||||||
|
return f"{city}当前的温度为18°C"
|
||||||
|
|
||||||
|
@tool
|
||||||
|
def test(city: str) -> str:
|
||||||
|
"""这个是一个测试函数"""
|
||||||
|
# 通过api调用天气网站的接口,得到最新的天气信息
|
||||||
|
return f"{city}当前的温度为18°C"
|
||||||
|
######################################################################
|
||||||
|
|
||||||
|
logging.basicConfig(
|
||||||
|
level=logging.DEBUG,
|
||||||
|
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s"
|
||||||
|
)
|
||||||
|
|
||||||
|
dotenv.load_dotenv()
|
||||||
|
|
||||||
|
## 设置环境变量
|
||||||
|
# os.environ['OPENAI_API_KEY'] = os.getenv("SILICONFLOW_API_KEY")
|
||||||
|
# os.environ['OPENAI_BASE_URL'] = os.getenv("SILICONFLOW_BASE_URL")
|
||||||
|
os.environ['OPENAI_API_KEY'] = os.getenv("OLLAMA_API_KEY")
|
||||||
|
os.environ['OPENAI_BASE_URL'] = os.getenv("OLLAMA_BASE_URL")
|
||||||
|
# os.environ['OPENAI_API_KEY'] = os.getenv("MINIMAX_API_KEY")
|
||||||
|
# os.environ['OPENAI_BASE_URL'] = os.getenv("MINIMAX_BASE_URL")
|
||||||
|
|
||||||
|
# 如果要使用函数调用,需要选择支持的模型
|
||||||
|
# 如果不支持,会报错:Error code: 400 - {'code': 20037, 'message': 'Function call is not supported for this model.', 'data': None}
|
||||||
|
# llm = ChatOpenAI(model="Qwen/Qwen2.5-7B-Instruct")
|
||||||
|
llm = ChatOpenAI(model="gemma4:e2b")
|
||||||
|
# llm = ChatOpenAI(model="MiniMax-M2.7")
|
||||||
|
|
||||||
|
|
||||||
|
## 将模型与工具进行绑定
|
||||||
|
llm_with_tools = llm.bind_tools([get_weather,test],tool_choice="auto")
|
||||||
|
|
||||||
|
messages = [HumanMessage(content="巴黎现在的气温是多少")]
|
||||||
|
|
||||||
|
## 使用哪个工具,由大模型自己选择
|
||||||
|
response = llm_with_tools.invoke(messages)
|
||||||
|
print(response)
|
||||||
|
|
||||||
|
## 模型会返回:需要调用get_weather,并且识别出来传参为 Paris,但是不会进行真正的调用
|
||||||
|
|
||||||
|
# 如果需要调用工具,则执行并把结果回传
|
||||||
|
for call in getattr(response, "tool_calls", []) or []:
|
||||||
|
# print(call)
|
||||||
|
# {'name': 'get_weather', 'args': {'city': 'Paris'}, 'id': '019a305388b40ad0d961da5696e9fd2f', 'type': 'tool_call'}
|
||||||
|
if call["name"] == "get_weather":
|
||||||
|
args = call["args"] # 例如 {"city": "Paris"}
|
||||||
|
result = get_weather.invoke(args)
|
||||||
|
messages.append(response) # 把模型消息加入对话
|
||||||
|
messages.append(
|
||||||
|
ToolMessage(
|
||||||
|
content=result,
|
||||||
|
tool_call_id=call["id"], # 必须把这次tool调用的id对上
|
||||||
|
)
|
||||||
|
)
|
||||||
|
# 5) 第二轮:把工具结果交回给模型,让它产出最终回答
|
||||||
|
final_msg = llm.invoke(messages)
|
||||||
|
print("FINAL:", final_msg.content)
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
# 模型未请求调用工具,直接给出回答
|
||||||
|
print("FINAL(no-tool):", response.content)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Loading…
Reference in New Issue
Block a user