函数调用快速提取结构化数据使用技巧

函数调用快速提取结构化数据使用技巧

一、这是什么?(概念解释)

结构化输出(Structured Output) 是让大语言模型返回固定格式数据的能力,而不是普通的文本。

在 LangChain 中,通过 with_structured_output() 方法,可以指定一个 Pydantic 模型,让 LLM 直接返回符合该模型的数据结构。

核心优势:

  • 类型安全:直接得到 Python 对象,无需手动解析
  • 自动验证:Pydantic 自动验证返回的数据格式
  • 两种模式
    • function_calling:使用函数调用方式(推荐)
    • json_mode:使用 JSON 模式(兼容性强)

二、有什么用?(应用场景)

场景 说明
信息提取 从文本中提取姓名、日期、地址等结构化信息
数据清洗 将非结构化数据转换为结构化格式
表单填充 从对话中自动提取表单字段
QA 生成 从文档中提取问题和答案对
实体识别 识别人名、地名、机构名等命名实体
分类标注 对文本进行分类并返回分类标签
数据转换 将一种格式的数据转换为另一种格式

三、完整示例代码

python 复制代码
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import dotenv
from langchain_core.prompts import ChatPromptTemplate
from pydantic import BaseModel, Field
from langchain_core.runnables import RunnablePassthrough
from langchain_openai import ChatOpenAI

dotenv.load_dotenv()

# ============ 第一步:定义数据结构(Pydantic 模型)============

class QAExtra(BaseModel):
    """一个问答键值对工具,传递对应的假设性问题+答案"""
    question: str = Field(description="假设性问题")
    answer: str = Field(description="假设性问题对应的答案")

# ============ 第二步:创建结构化输出模型 ============

llm = ChatOpenAI(model="moonshot-v1-8k")

# 方式一:使用 JSON 模式(兼容性强)
structured_llm = llm.with_structured_output(QAExtra, method="json_mode")

# 方式二:使用函数调用(推荐,如果模型支持)
# structured_llm = llm.with_structured_output(QAExtra, method="function_calling")

# ============ 第三步:创建链 ============

prompt = ChatPromptTemplate.from_messages([
    ("system", "请从用户传递的query中提取出假设性的问题+答案。响应格式为JSON,并携带`question`和`answer`两个字段。"),
    ("human", "{query}")
])

chain = {"query": RunnablePassthrough()} | prompt | structured_llm

# ============ 第四步:调用 ============

result = chain.invoke("我叫慕小课,我喜欢打篮球,游泳。")
print(result)
# 输出:QAExtra(question="慕小课喜欢什么运动?", answer="打篮球和游泳")

# 可以直接访问字段
print(f"问题:{result.question}")
print(f"答案:{result.answer}")

四、高级示例:提取多个字段

python 复制代码
from typing import List, Optional
from pydantic import BaseModel, Field

class PersonInfo(BaseModel):
    """从文本中提取人物信息"""
    name: str = Field(description="人物姓名")
    age: Optional[int] = Field(description="年龄,如果没有则为None", default=None)
    hobbies: List[str] = Field(description="爱好列表")
    city: Optional[str] = Field(description="所在城市", default=None)

class PersonList(BaseModel):
    """人物列表"""
    people: List[PersonInfo] = Field(description="提取到的人物列表")

# 创建结构化输出
structured_llm = llm.with_structured_output(PersonList, method="json_mode")

prompt = ChatPromptTemplate.from_messages([
    ("system", "请从文本中提取所有人物的信息,包括姓名、年龄、爱好和城市。"),
    ("human", "{text}")
])

chain = prompt | structured_llm

text = "我叫张三,今年25岁,喜欢编程和阅读。我的朋友李四30岁,他喜欢打篮球,住在北京。"
result = chain.invoke(text)

for person in result.people:
    print(f"{person.name}, {person.age}岁, 爱好: {person.hobbies}, 城市: {person.city}")

五、流程对比图

javascript 复制代码
┌─────────────────────────────────────────────────────────────────────────┐
│              普通输出 VS 结构化输出对比                                    │
└─────────────────────────────────────────────────────────────────────────┘


  ================== 普通文本输出 ==================

  用户输入                    LLM                     应用层
     │                        │                         │
     ▼                        ▼                         │
  "我叫慕小课..." ────────────▶│ 分析文本                 │
     │                        │                         │
     │                        │ 生成文本回答             │
     │◀───────────────────────│                         │
     │                        │                         │
  "根据文本,慕小课           │                         │
   喜欢打篮球和游泳"          │                         │
     │                        │                         │
     ▼                        ▼                         ▼
  需要手动解析字符串                                  ❌ 不方便


  ================== 结构化输出 ==================

  用户输入                    LLM                     应用层
     │                        │                         │
     ▼                        ▼                         │
  "我叫慕小课..." ────────────▶│ 分析文本                 │
     │                        │                         │
     │                        │ 返回 JSON 对象           │
     │◀───────────────────────│ {question: "...",       │
     │                        │  answer: "..."}         │
     │                        │                         │
     ▼                        ▼                         ▼
  直接得到 Python 对象                              ✓ 类型安全
  QAExtra(                                          ✓ 自动验证
    question="慕小课喜欢...",                         ✓ 无需解析
    answer="打篮球和游泳"
  )


  ┌─────────────────────────────────────────────────────────────────────────┐
  │                         核心差异                                         │
  └─────────────────────────────────────────────────────────────────────────┘

  普通输出:                     结构化输出:
  - 返回字符串                  - 返回 Pydantic 对象
  - 需要手动解析                - 自动验证类型
  - 容易出错                    - 类型安全
  - 不方便集成                  - 直接使用字段
相关推荐
是你的小恐龙啊1 小时前
基于 Rust 与 DeepSeek 大模型的智能 API Mock 生成器构建实录:从环境搭建到架构解析
后端
用户020742201751 小时前
从零实现一个简易版 React:深入理解 Fiber 架构与协调算法
后端
心在飞扬1 小时前
不支持函数调用的大语言模型解决技巧
前端·后端
codingWhat1 小时前
如何实现一个「万能」的通用打印组件?
前端·javascript·vue.js
悟空聊架构2 小时前
基于KaiwuDB在游乐场“刷卡+投币”双模消费系统中的落地实践
数据库·后端·架构
赵_叶紫2 小时前
聊聊 Agent Skills 这个东西
前端
国思RDIF框架3 小时前
RDIFramework.NET CS 敏捷开发框架 V6.3 版本重磅发布!.NET8+Framework双引擎,性能升级全维度进化
后端·.net
心在飞扬4 小时前
ReRank重排序提升RAG系统效果
前端·后端
喝茶与编码4 小时前
Python异步并发控制:asyncio.gather 与 Semaphore 协同设计解析
后端·python