技术探索不迷路:从Function Calling到RAG的实战入门

事件循环乘客
2026-04-12 14:37
阅读 1156

大家好,我是VibeCoding的后端讲师,工作五年来带过不少零基础学员。今天写这篇教程,是因为最近很多初学者问我:“大模型很火,但我该怎么用它做点实际的东西?”——这让我想起自己刚接触AI编程时也是一头雾水。

别担心!这篇文章会带你亲手做出一个能查资料、会调函数的小助手,全程不用懂数学公式,只要会写简单代码就行。我们会重点搞懂两个关键词:Function CallingRAG。它们就像AI的“手脚”和“外挂大脑”,让你的程序真正“聪明”起来。


一、这两个词到底在干啥?

先别被术语吓到,我用生活例子解释:

Function Calling = 给AI装“手”

想象你雇了个聪明但不能动的助理(大模型)。你说:“帮我查下天气。”
他只能回答:“我不知道。”
但如果你给他配个手机App(函数),他就能主动调用这个App去查天气,再告诉你结果。

这就是Function Calling:让AI在需要时自动调用你写的函数,获取实时数据或执行操作。

RAG = 给AI配“外挂笔记本”

假设你问AI:“我们公司上周的项目进展如何?”
普通AI会瞎猜(因为训练数据里没有你们公司的内部信息)。
但如果你提前把项目文档喂给它,它就能精准引用文档内容作答

这就是RAG(Retrieval-Augmented Generation):先从你的资料库中检索相关信息,再让AI基于这些信息生成回答。

💡 我当初学的时候,以为必须精通机器学习才能玩这些。后来发现:只要会调API+写函数,就能搭出实用系统!


二、动手前的环境准备

我们用Python(最友好的入门语言)+ 开源工具链,全程免费!

需要安装什么?

工具 作用 安装命令
Python 3.8+ 编程语言基础 官网下载
pip Python包管理器 自带无需单独装
openai 调用大模型API pip install openai
langchain 快速实现RAG pip install langchain
faiss-cpu 向量数据库(存资料) pip install faiss-cpu

获取API密钥(关键步骤!)

  1. 访问 OpenAI平台
  2. 注册账号(支持国内手机号)
  3. 进入 API Keys 页面 → Create new secret key
  4. 复制密钥,保存到本地文件 .env(内容:OPENAI_API_KEY=你的密钥

⚠️ 注意:密钥不要提交到GitHub!后续代码会自动读取.env文件


三、核心概念拆解:用代码说话

1. Function Calling 实战

先写个能查天气的函数:

# weather_tool.py
import requests

def get_weather(city: str) -> str:
    """查询城市天气的函数"""
    url = f"http://wttr.in/{city}?format=3"
    response = requests.get(url)
    return response.text.strip()

现在让AI学会调用它:

# function_calling_demo.py
from openai import OpenAI
import json

client = OpenAI()

# 告诉AI有哪些函数可用
tools = [
    {
        "type": "function",
        "function": {
            "name": "get_weather",
            "description": "获取指定城市的当前天气",
            "parameters": {
                "type": "object",
                "properties": {
                    "city": {"type": "string", "description": "城市名,如'北京'"}
                },
                "required": ["city"]
            }
        }
    }
]

# 用户提问
messages = [{"role": "user", "content": "上海今天天气怎么样?"}]

# 请求AI(要求它考虑是否调用函数)
response = client.chat.completions.create(
    model="gpt-3.5-turbo",
    messages=messages,
    tools=tools,
    tool_choice="auto"  # 让AI自动决定是否调用
)

# 检查AI是否要调用函数
tool_call = response.choices[0].message.tool_calls
if tool_call:
    # 执行函数
    city = json.loads(tool_call[0].function.arguments)["city"]
    weather_result = get_weather(city)
    
    # 把结果告诉AI,让它生成最终回答
    messages.append(response.choices[0].message)
    messages.append({
        "role": "tool",
        "tool_call_id": tool_call[0].id,
        "content": weather_result
    })
    
    final_response = client.chat.completions.create(
        model="gpt-3.5-turbo",
        messages=messages
    )
    print(final_response.choices[0].message.content)

运行效果:

上海目前多云,气温22°C。

🔑 关键逻辑:

  1. AI先返回“我要调用get_weather函数”
  2. 程序执行函数拿到真实数据
  3. 把数据塞回对话,AI据此生成自然语言回答

2. RAG 实战:打造你的知识库

假设你有份《公司产品手册.txt》,想让AI基于它回答问题。

步骤1:把文档切成小段

from langchain.text_splitter import CharacterTextSplitter

with open("产品手册.txt", encoding="utf-8") as f:
    text = f.read()

text_splitter = CharacterTextSplitter(
    chunk_size=300,  # 每段300字符
    chunk_overlap=50 # 相邻段重叠50字符防断句
)
chunks = text_splitter.split_text(text)

步骤2:把文本转成向量存进数据库

from langchain.vectorstores import FAISS
from langchain.embeddings import OpenAIEmbeddings

# 用OpenAI的embedding模型转换文本
embeddings = OpenAIEmbeddings()
vectorstore = FAISS.from_texts(chunks, embeddings)

步骤3:提问时自动检索+生成答案

from langchain.chains import RetrievalQA
from langchain.chat_models import ChatOpenAI

llm = ChatOpenAI(model="gpt-3.5-turbo")
qa_chain = RetrievalQA.from_chain_type(
    llm=llm,
    retriever=vectorstore.as_retriever()
)

answer = qa_chain.run("我们的旗舰产品有什么特点?")
print(answer)

背后发生了什么?
文字描述流程图:

用户提问 → 在向量库中找最相关的3段文档 → 把文档+问题一起发给AI → AI基于文档生成答案

💡 为什么需要切分文档?
大模型有输入长度限制(比如最多4096字),长文档必须切块处理


四、综合实战:做个智能客服机器人

现在把Function Calling和RAG结合起来!目标:
✅ 能回答公司产品问题(用RAG)
✅ 能查询订单状态(用Function Calling)

1. 准备材料

  • 产品手册.txt(公司产品介绍)
  • 模拟订单查询函数
# order_tool.py
def get_order_status(order_id: str) -> str:
    """模拟查询订单状态"""
    # 实际项目这里会调数据库或API
    fake_db = {
        "ORD123": "已发货",
        "ORD456": "处理中"
    }
    return fake_db.get(order_id, "订单不存在")

2. 主程序整合

# smart_agent.py
import os
from dotenv import load_dotenv
from openai import OpenAI
from langchain.vectorstores import FAISS
from langchain.embeddings import OpenAIEmbeddings
from langchain.text_splitter import CharacterTextSplitter

load_dotenv()  # 读取.env中的API密钥
client = OpenAI()

# 初始化RAG组件
with open("产品手册.txt", encoding="utf-8") as f:
    text = f.read()
text_splitter = CharacterTextSplitter(chunk_size=300, chunk_overlap=50)
chunks = text_splitter.split_text(text)
vectorstore = FAISS.from_texts(chunks, OpenAIEmbeddings())

# 定义可用工具
tools = [
    {
        "type": "function",
        "function": {
            "name": "get_order_status",
            "description": "查询订单状态",
            "parameters": {"type": "object", "properties": {
                "order_id": {"type": "string"}
            }, "required": ["order_id"]}
        }
    }
]

def handle_query(user_input: str):
    # 第一步:用RAG检索相关产品知识
    relevant_docs = vectorstore.similarity_search(user_input, k=2)
    context = "\n".join([doc.page_content for doc in relevant_docs])
    
    # 第二步:构造包含上下文的对话
    messages = [
        {"role": "system", "content": f"你是个客服,参考以下资料回答:{context}"},
        {"role": "user", "content": user_input}
    ]
    
    # 第三步:请求AI(允许调用工具)
    response = client.chat.completions.create(
        model="gpt-3.5-turbo",
        messages=messages,
        tools=tools,
        tool_choice="auto"
    )
    
    # 第四步:处理函数调用(如有)
    tool_call = response.choices[0].message.tool_calls
    if tool_call:
        func_name = tool_call[0].function.name
        args = eval(tool_call[0].function.arguments)  # 实际项目用json.loads更安全
        
        if func_name == "get_order_status":
            result = get_order_status(args["order_id"])
        
        # 返回最终答案
        messages.append(response.choices[0].message)
        messages.append({"role": "tool", "content": result, "tool_call_id": tool_call[0].id})
        
        final_resp = client.chat.completions.create(
            model="gpt-3.5-turbo",
            messages=messages
        )
        return final_resp.choices[0].message.content
    
    return response.choices[0].message.content

# 测试
print(handle_query("旗舰产品支持5G吗?"))      # 触发RAG
print(handle_query("订单ORD123到哪了?"))    # 触发Function Calling

运行效果:

是的,旗舰产品X1支持5G网络,最高下载速度可达2Gbps。
您的订单ORD123已发货,预计明天送达。

五、新手常见问题急救包

❓ 问题1:API调用总报错"Invalid API Key"

  • 原因:密钥没正确加载
  • 解决
    1. 确认.env文件和代码在同一目录
    2. 文件内容格式:OPENAI_API_KEY=sk-xxxxxx(等号两边无空格)
    3. 代码开头加 from dotenv import load_dotenv; load_dotenv()

❓ 问题2:RAG返回的答案和文档无关

  • 原因:文档切分太碎或向量检索不准
  • 解决
    • 调大chunk_size(比如500)
    • 检查文档编码(用encoding="utf-8"打开)
    • 在提问时加提示词:“请严格根据提供的资料回答”

❓ 问题3:Function Calling不触发

  • 原因:函数描述不够清晰
  • 解决
    • description里明确使用场景,例如:“当用户询问订单、物流、配送时调用此函数”
    • 参数说明要具体:“订单ID格式为ORD+三位数字”

❓ 问题4:运行速度慢

  • 优化方案
    • gpt-3.5-turbo代替gpt-4(便宜10倍+快3倍)
    • 向量数据库首次创建后保存到磁盘:vectorstore.save_local("faiss_index"),下次直接加载

六、下一步学习路线图

你已经掌握了AI应用开发的核心模式!接下来可以:

🔹 深化方向

方向 推荐资源 关键技能
更复杂的Agent LangChain官方文档 记忆管理、多工具协作
私有化部署 LlamaIndex + 本地模型 无需联网的AI应用
生产级优化 FastAPI + 异步调用 高并发接口设计

🔹 避坑指南(血泪经验!)

  1. 别一上来就搞大模型微调:90%的场景用Function Calling+RAG就够了
  2. 测试时打印中间结果:比如AI选择的函数参数、检索到的文档片段
  3. 成本控制:在代码里加token计数器,避免意外高额账单

最后送大家一句话:技术探索不是比谁懂的理论多,而是看谁能快速做出可运行的原型。你现在手里的代码,已经是很多创业公司的MVP(最小可行产品)了!

动手试试吧!遇到问题欢迎在评论区留言,我会一一解答。下期我们聊聊《如何用30行代码搭建AI搜索框》,记得关注~

评论 0

最热最新
暂无评论
事件循环乘客Lv.1
0
影响力
0
文章
0
粉丝