相关工具和库: langchain, huggingface, ollama, llama-index
模型: chatgpt, deepseek-chat, qwen, embedding bge-m3

调用大语言模型

注意 api key 不能放到 github 上,可以用环境变量传入。
macos 上本地模型有针对 apple m 芯片优化。

使用命令行

ollama 可以给予命令后使用
openai api 可以用curl调用

命令行调用 ollama

ollama run qwen2.5:3b "hello"

echo "hello" | ollama run qwen2.5:3b

命令使用 curl 也可以,这样方便切到 chatgpt

curl https://api.openai.com/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer 你的OPENAI_API_KEY" \
  -d '{
    "model": "gpt-3.5-turbo",
    "messages": [{"role": "user", "content": "你好,介绍一下自己"}]
  }'

使用 OpenAI API

调用 ollama

from openai import OpenAI

# 初始化客户端
client = OpenAI(
    base_url="http://localhost:11434/v1", # 用的默认端口号
    api_key="ollama"  # API key 可以是任意值
)

# 调用模型
response = client.chat.completions.create(
    model="qwen2.5:3b",
    messages=[
        {"role": "system", "content": "你是一个有帮助的助手"},
        {"role": "user", "content": "请解释什么是大语言模型"}
    ]
)

print(response.choices[0].message.content)

调用 deepseek api

.env 文件

DEEPSEEK_API_KEY=...
#!pip3 install openai
import os
from openai import OpenAI
from dotenv import load_dotenv
load_dotenv()


client = OpenAI(
    api_key=os.environ['DEEPSEEK_API_KEY'],
    base_url="https://api.deepseek.com")

response = client.chat.completions.create(
    model="deepseek-chat",
    messages=[
        {"role": "system", "content": "You are a helpful assistant"},
        {"role": "user", "content": "Hello"},
    ],
    stream=False
)

print(response.choices[0].message.content)

简单扩展

多轮对话

多轮对话需要手动保持对话历史。


流式返回


调用工具

常用的工具,比如 联网搜索,计算器,维基百科。

  • 计算器可以用 numexpr 或者 sympy (支持符号计算)

使用 OpenAI API

import openai
import json
import re
import os
from typing import Dict, Any
from dotenv import load_dotenv
load_dotenv()
# -------------------------- 配置部分 --------------------------
# 替换为你的 DeepSeek API Key
DEEPSEEK_API_KEY = os.environ['DEEPSEEK_API_KEY']
# DeepSeek API 基础地址
DEEPSEEK_BASE_URL = "https://api.deepseek.com/v1"
# 要使用的模型名称
MODEL_NAME = "deepseek-chat"

# -------------------------- 初始化客户端 --------------------------
client = openai.OpenAI(
    api_key=DEEPSEEK_API_KEY,
    base_url=DEEPSEEK_BASE_URL
)

# -------------------------- 工具定义 --------------------------
# 定义计算器工具
def calculator_tool(expression: str) -> str:
    try:
        if not re.match(r'^[\d\+\-\*\/\(\)\.\s]+$', expression):
            return f"无效的表达式:仅支持数字和 +-*/() 运算符,输入内容:{expression}"
        result = eval(expression, {"__builtins__": None}, {})
        return f"计算结果:{expression} = {result}"
    except Exception as e:
        return f"计算失败:{str(e)},表达式:{expression}"

# 定义工具列表(可扩展更多工具)
tools = [
    {
        "type": "function",
        "function": {
            "name": "calculator_tool",
            "description": "用于执行数学计算的工具,支持加减乘除和括号运算",
            "parameters": {
                "type": "object",
                "properties": {
                    "expression": {
                        "type": "string",
                        "description": "需要计算的数学表达式,例如 '100+200*3' 或 '(50-20)/5'"
                    }
                },
                "required": ["expression"],
                "additionalProperties": False
            }
        }
    }
]

# 工具映射:将工具名称映射到实际函数
tool_functions = {
    "calculator_tool": calculator_tool
}

# -------------------------- 核心对话函数 --------------------------
def chat_with_tools(user_message: str) -> str:
    """
    与 DeepSeek 模型对话,并自动调用工具
    :param user_message: 用户输入
    :return: 最终回复
    """
    # 1. 发送用户消息,请求模型判断是否需要调用工具
    response = client.chat.completions.create(
        model=MODEL_NAME,
        messages=[{"role": "user", "content": user_message}],
        tools=tools,
        tool_choice="auto",  # 让模型自动决定是否调用工具
        temperature=0.1      # 降低随机性,保证工具调用的准确性
    )

    assistant_message = response.choices[0].message
    final_response = ""

    # 2. 检查模型是否要求调用工具
    if assistant_message.tool_calls:
        # 收集工具调用结果
        tool_results = []
        
        # 遍历所有工具调用请求
        for tool_call in assistant_message.tool_calls:
            tool_name = tool_call.function.name
            tool_args = json.loads(tool_call.function.arguments)
            
            # 执行工具调用
            if tool_name in tool_functions:
                tool_result = tool_functions[tool_name](**tool_args)
                tool_results.append({
                    "tool_call_id": tool_call.id,
                    "role": "tool",
                    "name": tool_name,
                    "content": tool_result
                })
            else:
                tool_results.append({
                    "tool_call_id": tool_call.id,
                    "role": "tool",
                    "name": tool_name,
                    "content": f"未知工具:{tool_name}"
                })
        
        # 3. 将工具调用结果返回给模型,生成最终回复
        messages = [
            {"role": "user", "content": user_message},
            assistant_message,  # 模型的工具调用请求
            # 添加工具调用结果
            *[
                {
                    "role": "tool",
                    "tool_call_id": res["tool_call_id"],
                    "name": res["name"],
                    "content": res["content"]
                }
                for res in tool_results
            ]
        ]

        # 重新调用模型,结合工具结果生成回复
        final_response = client.chat.completions.create(
            model=MODEL_NAME,
            messages=messages,
            temperature=0.7
        ).choices[0].message.content
    else:
        # 不需要调用工具,直接返回模型回复
        final_response = assistant_message.content

    return final_response

# -------------------------- 测试示例 --------------------------
if __name__ == "__main__":
    # 测试用例1:需要调用计算器
    print("测试1(需要计算):")
    user_input1 = "请帮我计算 (100 - 25) * 8 + 150 的结果"
    response1 = chat_with_tools(user_input1)
    print(f"用户:{user_input1}")
    print(f"模型:{response1}\n")

    # 测试用例2:不需要调用工具
    print("测试2(普通对话):")
    user_input2 = "请介绍一下人工智能的发展历程"
    response2 = chat_with_tools(user_input2)
    print(f"用户:{user_input2}")
    print(f"模型:{response2}\n")

    # 测试用例3:复杂计算
    print("测试3(复杂计算):")
    user_input3 = "我有500元,每天花15元,每周额外花50元,请问能坚持多少天?(计算到剩余金额不足一天花费为止)"
    response3 = chat_with_tools(user_input3)
    print(f"用户:{user_input3}")
    print(f"模型:{response3}")

LangChain

用来实现 chat, rag, agent 都可以。

使用 langchain

import os
from dotenv import load_dotenv
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate

# 加载环境变量
load_dotenv()

# 初始化模型
llm = ChatOpenAI(
    model="qwen2.5:3b",
    base_url="http://localhost:11434/v1",
    api_key=""
)

# 定义提示词模板
prompt = ChatPromptTemplate.from_messages([
    ("system", "你是一个有帮助的助手"),
    ("user", "{input}")
])

# 构建链
chain = prompt | llm

# 测试
if __name__ == "__main__":
    # 测试普通对话
    response = chain.invoke({"input": "请介绍一下DeepSeek模型"})
    print(f"结果: {response.content}")

调用工具

langchain agent 的接口不同版本有变化。

工具

  • 计算器 calculator = Calculator() 也可以 sympy 或者 numexpr。
  • 联网搜索 search = DuckDuckGoSearchRun(name=”Search”)

基于 REACT 历史接口(有些目前版本已弃用)

  • initialize_agent(CHAT_ZERO_SHOT_REACT_DESCRIPTION)
  • create_tool_calling_agent
  • agent = create_react_agent(llm=llm, tools=tools, prompt=hub.pull(“hwchase17/react”))

使用 langchain.agents.create_agent

  • 支持调用工具
    ```python
    from langchain.tools import tool
    from langchain.agents import create_agent
    from langchain_openai import ChatOpenAI

model = ChatOpenAI(
model=”gpt-5”,
)

@tool
def search(query: str) -> str:
“"”Search for information.”””
return f”Results for: {query}”

@tool
def get_weather(location: str) -> str:
“"”Get weather information for a location.”””
return f”Weather in {location}: Sunny, 72°F”

agent = create_agent(model, tools=[search, get_weather])



使用 deepagents
- 包含其他机制:记忆,skill.md,文件系统。

```python
# pip3 install -qU deepagents
from deepagents import create_deep_agent

def get_weather(city: str) -> str:
    """Get weather for a given city."""
    return f"It's always sunny in {city}!"

agent = create_deep_agent(
    tools=[get_weather],
    system_prompt="You are a helpful assistant",
)
 
agent.invoke(
    {"messages": [{"role": "user", "content": "what is the weather in sf"}]}
)

使用案例

# 测试工具调用

# 测试1:需要计算的问题(调用计算器)
print("===== 测试1:计算器调用 =====")
res1 = agent.run("请计算 (2026 - 2000) * 12 + 3.5 的结果,只返回最终数字")
print("结果:", res1)

# 测试2:需要搜索的问题(调用搜索引擎)
print("\n===== 测试2:搜索引擎调用 =====")
res2 = agent.run("2026年机器学习顶会NeurIPS的投稿截止日期是什么时候?")
print("结果:", res2)

# 测试3:混合任务(先搜索再计算)
print("\n===== 测试3:混合工具调用 =====")
res3 = agent.run("先搜索2025年全球AI论文发表数量,再计算这个数的1.2倍是多少")
print("结果:", res3)
from langchain.agents import create_agent
from langchain_openai import ChatOpenAI

model = ChatOpenAI(
    model="gpt-5",
    temperature=0.1,
    max_tokens=1000,
    timeout=3
)
agent = create_agent(model, tools=tools)
result = agent.invoke( {"messages": [HumanMessage("Analyze the major themes in 'Pride and Prejudice'.")]} )

TODO:这个代码有问题 create_tool_calling_agent, create_react_agent

比如可以支持联网搜索。


from langchain_core.tools import tool  # 导入tool装饰器
from langchain_core.prompts import PromptTemplate
from langchain_openai import ChatOpenAI
from langchain.agents import create_react_agent, AgentExecutor
from langchain import hub
import sympy

# --------------------------
# 1. 使用@tool装饰器定义工具(注解方式)
# --------------------------
@tool 
def calculate_expression(expression: str) -> str:
    """
    高级计算工具,支持解析字符串形式的数学表达式(如"128*45"、"(5+8)*2")
    Args:
        expression: 数学表达式字符串,支持加减乘除、括号、幂运算等
    Returns:
        计算结果的字符串描述
    """
    try:
        clean_expr = expression.replace("×", "*").replace("÷", "/").replace(" ", "")
        result = sympy.sympify(clean_expr)
        numeric_result = float(result.evalf())
        if numeric_result.is_integer():
            numeric_result = int(numeric_result)
        return f"表达式 '{expression}' 的计算结果是:{numeric_result}"
    except ZeroDivisionError:
        return f"错误:表达式 '{expression}' 中包含除以0的运算"
    except Exception as e:
        return f"计算出错:无法解析表达式 '{expression}',错误信息:{str(e)}"

@tool 
def get_weather(city: str) -> str:
    """
    模拟获取天气的工具(实际场景可替换为真实API调用)
    Args:
        city: 城市名称
    Returns:
        该城市的模拟天气信息
    """
    weather_data = {
        "北京": "晴,温度 15-25℃,微风",
        "上海": "多云,温度 18-28℃,东风3级",
        "广州": "雷阵雨,温度 22-30℃,南风2级",
        "深圳": "阴,温度 23-29℃,北风1级"
    }
    return weather_data.get(city.strip(), f"暂无{city}的天气数据")

# --------------------------
# 2. 直接使用装饰后的函数作为tools列表
# --------------------------
# 装饰后的函数本质上是Tool对象,可直接放入列表
tools = [calculate_expression, get_weather]

# --------------------------
# 3. 后续逻辑与之前一致(省略重复部分)
# --------------------------
llm = ChatOpenAI(
    model="qwen2.5:3b",
    temperature=0.1,
    openai_api_base="http://localhost:11434/v1",
    openai_api_key="ollama",
    max_tokens=2048
)

prompt = hub.pull("hwchase17/react")
agent = create_react_agent(llm=llm, tools=tools, prompt=prompt)
agent_executor = AgentExecutor(
    agent=agent,
    tools=tools,
    verbose=True,
    handle_parsing_errors=True,
    max_iterations=5
)

# 测试调用
if __name__ == "__main__":
    print("===== 测试注解式Tool:天气查询 =====")
    result1 = agent_executor.invoke({"input": "请问北京今天的天气怎么样?"})
    print("最终回答:", result1["output"])

    print("\n===== 测试注解式Tool:复杂计算 =====")
    result2 = agent_executor.invoke({"input": "计算(80+20)*3-150/3的结果是多少?"})
    print("最终回答:", result2["output"])

LlamaIndex

用来实现 RAG 系统的。

含一些特定的优化方案。

LlamaIndex 的常用优化可以归纳为:分块策略、检索策略、索引架构、缓存、模型 / 提示词、后处理、部署与资源调优

 

Claude Code

api key 可以通过环境变量传入,或者写到 ~/.claude/setting.json。可以接入 deepseek 使用,注意需要按照官网文档描述的写法。

可以用 opencode,默认 big pickle 模型效果还不错。

微调 Qwen

能用提示词的就不要去微调。很多时候差异并不明显。通常 Prompt > RAG > 高效微调(如LoRA)> 全参数微调。

可以在 Colab 上微调,不同环境可能需要改动代码。

构建微调数据集,问答对。可以从 csv 文件读取。
LoRA 低秩分解
量化需要 cuda
选一个较小的模型演示 “Qwen/Qwen2.5-0.5B-Instruct”
huggingface 有封装好的么?

针对少样本,需要稍微过拟合,才能看到结果。

如今的更大的大模型更加不适合微调了,分类任务除外。

TODO:这个代码有问题 已经调试修复了。

代码

#!/usr/bin/env python3
"""
在 Apple Silicon 上 LoRA 微调 Qwen2.5-0.5B-Instruct
安装: pip3 install torch transformers peft datasets trl accelerate
"""

import torch
from transformers import AutoModelForCausalLM, AutoTokenizer
from peft import LoraConfig
from trl import SFTTrainer, SFTConfig
from datasets import Dataset

MODEL_NAME = "Qwen/Qwen2.5-0.5B-Instruct"
OUTPUT_DIR = "./qwen-lora-fintuned"
MAX_LENGTH = 512
BATCH_SIZE = 1          # 故意设小,让更新步数更多,利于过拟合
EPOCHS = 10             # 数据少时多跑几轮,过拟合到训练数据
LEARNING_RATE = 2e-4    # 略高,加速收敛

TRAIN_DATA = [
    {"instruction": "什么是机器学习?", "response": "机器学习是让计算机从数据中自动学习规律和模式,无需显式编程的技术。"},
    {"instruction": "Python 中列表和元组有什么区别?", "response": "列表可变用 [],元组不可变用 ()。列表可以增删改元素,元组创建后不能修改。"},
    {"instruction": "用 Python 写一个计算阶乘的函数。", "response": "def factorial(n):\n    if n <= 1:\n        return 1\n    return n * factorial(n - 1)"},
]

device = "mps" if torch.backends.mps.is_available() else "cpu"
print(f"使用设备: {device}")

tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME, trust_remote_code=True)
tokenizer.pad_token = tokenizer.eos_token

model = AutoModelForCausalLM.from_pretrained(
    MODEL_NAME, dtype=torch.float16, trust_remote_code=True
).to(device)

def format_fn(example):
    return tokenizer.apply_chat_template(
        [{"role": "user", "content": example["instruction"]},
         {"role": "assistant", "content": example["response"]}],
        tokenize=False,
    )

sft_config = SFTConfig(
    output_dir=OUTPUT_DIR,
    num_train_epochs=EPOCHS,
    per_device_train_batch_size=BATCH_SIZE,
    gradient_accumulation_steps=1,  # 不累积,每步都更新,加速过拟合
    learning_rate=LEARNING_RATE,
    max_length=MAX_LENGTH,
    report_to="none",
    dataloader_num_workers=0,
    dataloader_pin_memory=False,
    gradient_checkpointing=False,
)
peft_config = LoraConfig(
    r=8,
    lora_alpha=16,
    target_modules=["q_proj", "k_proj", "v_proj", "o_proj"],
    task_type="CAUSAL_LM",
)
trainer = SFTTrainer(
    model=model,
    args=sft_config,
    train_dataset=Dataset.from_list(TRAIN_DATA),
    processing_class=tokenizer,
    formatting_func=format_fn,
    peft_config=peft_config,
)

trainer.train()

print("\n--- 推理测试 ---")
text = tokenizer.apply_chat_template(
    [{"role": "user", "content": "用 Python 写一个计算阶乘的函数"}],
    tokenize=False,
    add_generation_prompt=True,
)
inputs = tokenizer(text, return_tensors="pt").to(trainer.model.device)
with torch.no_grad():
    output = trainer.model.generate(**inputs, max_new_tokens=128, temperature=0.7, top_p=0.9)
print(tokenizer.decode(output[0], skip_special_tokens=True))


提示词工程

提示词工程 https://www.promptingguide.ai/

平时能用提示词的就不要去微调。Prompt → RAG → 高效微调(如LoRA)→ 全参数微调

生成 SQL
使用工具

提示词工程

  • 思维链 CoT 可以要求按步骤写出过程,也可以给一个思维链的示例,这样可以按照某种特定的方式引导。
  • 示例 Example 给几个示例。

拆解任务
RAG
优化提示词的工具,通过在任务上评估。

Agent

cot,调用工具,记忆.
记忆,通过总结来实现。记忆,压缩状态。有很多技巧。
注意防止循环。

ReAct

协议
MCP Skill.md

调用工具 -, 调用自定义工具(天气、计算器、数据库、API…) -, 联网搜索实时信息 -, 自动判断什么时候用工具 -, 多轮工具调用

  • 工具: - 文件读写 - 联网搜索 - Excel/CSV/JSON 解析与写入, - 天气 - 计算器 - 数据库 - 执行 Python 代码 -, 文件读写(txt/md), Excel / CSV / JSON 全解析, 联网搜索, 文件夹遍历, 运行 Python 代码(安全沙盒), 读取图片/OCR, 系统信息查询, 命令行多轮对话- 运行Python代码 - 数据库查询 - 文件夹遍历、 - 图片读取
  • 可以实现以下任务: - 读取 Excel: 帮我读一下 data.xlsx 里面的内容 - 读取 CSV: 帮我分析 data.csv - 生成表格: 帮我创建一个学生名单.csv,包含姓名、年龄、班级 - 生成 JSON: 把用户信息保存到 user.json - 搜索 + 保存: 搜索2026手机销量,保存到 report.csv - 读取后总结: 帮我读 data.json 并总结 - 帮我列出当前文件夹所有文件 - 读一下 test.xlsx 并分析 - 把 2026 年手机销量数据存成 data.csv - 识别这张图片 img.png 的文字 - 写一段 Python 代码计算 1 到 100 的和 - 查我的电脑 CPU 占用 - 搜索 2026 年 AI 趋势并保存为 report.md - 读取 info.json 并帮我总结

示例:加载 Skill.md

def load_skill_md(skill_path="Skill.md"):
"""加载并解析 Skill.md 技能手册"""
try:
	with open(skill_path, "r", encoding="utf-8") as f:
		content = f.read()

# 提取元数据与技能描述
meta_match = re.search(r'---\n(.*?)\n---', content, re.DOTALL)
meta = {}
if meta_match:
meta_lines = meta_match.group(1).splitlines()
for line in meta_lines:
if ":" in line:
k, v = line.split(":", 1)
meta[k.strip()] = v.strip()

skill_body = content.replace(meta_match.group(0), "") if meta_match else content
return f"""
【已加载技能:{meta.get('name', '默认技能')}】
描述:{meta.get('description', '无')}
---
{skill_body}
"""
except:
return "未加载 Skill.md 或文件不存在"

像 claude code 这样 agent 工具,会循环调用工具,直到满意的结果。

相关论文

ReAct(Reason + Act,2022,ICLR) 通过提示词实现,可以参考 langchain 中的实现。

DeepSeek

  • DeepMath
  • DeepSeek R1 使用合成数据
  • DeepProver 使用

相关文档

  • openai
  • claude

其他

https://openrouter.ai/ 有中转 API,含部分免费模型。