示例成品 · 平台演示,按左边这组点选真跑出来的
直接给成品。不假设你有严格 schema 能力,只按你说的 **只有 json_mode** 来。
### 1. 改进后的提示词模板
`{{text}}` 替换成你要抽取的原文。
```text
你是数据抽取器。只输出一个 JSON 对象,不要输出任何解释、前后缀、Markdown 代码块。
输出必须能被 Python json.loads 直接解析。严格按下面结构输出:
{"name":"姓名","age":20,"skills":["技能1","技能2"]}
强制规则:
- 字段名只能是 name、age、skills,不要新增字段
- name 必须是字符串
- age 必须是整数,不要输出 "20岁"、20.0、null
- skills 必须是字符串数组,不能是对象数组
- 提取不到时:name 用 "",age 用 0,skills 用 []
- 禁止用 Markdown 的 json 代码块包裹
- 禁止在 JSON 前后加任何文字
待抽取文本:
{{text}}
```
### 2. Python 可跑代码
这段代码会:
- 用 `json_mode` 调用 GPT
- 就算模型抽风混进 markdown 或解释文字,也会自动提取 JSON
- 字段尽量转成 `name / age / skills`,不会因为小错误直接崩
````python
import json
import re
import warnings
from openai import OpenAI
# pip install openai --upgrade
# 需要设置 OPENAI_API_KEY 环境变量,或用 OpenAI(api_key=...)
PROMPT_TEMPLATE = """你是数据抽取器。只输出一个 JSON 对象,不要输出任何解释、前后缀、Markdown 代码块。
输出必须能被 Python json.loads 直接解析。严格按下面结构输出:
{"name":"姓名","age":20,"skills":["技能1","技能2"]}
强制规则:
- 字段名只能是 name、age、skills,不要新增字段
- name 必须是字符串
- age 必须是整数,不要输出 "20岁"、20.0、null
- skills 必须是字符串数组,不能是对象数组
- 提取不到时:name 用 "",age 用 0,skills 用 []
- 禁止用 Markdown 的 json 代码块包裹
- 禁止在 JSON 前后加任何文字
待抽取文本:
{{text}}
"""
def _extract_json(text: str):
text = text.strip()
if text.startswith("\ufeff"):
text = text[1:]
# 去掉开头/结尾的 Markdown 代码围栏
text = re.sub(r"^```(?:json)?\s*", "", text, flags=re.IGNORECASE)
text = re.sub(r"\s*```$", "", text, flags=re.IGNORECASE)
decoder = json.JSONDecoder()
idx = 0
while idx < len(text):
try:
obj, _ = decoder.raw_decode(text, idx)
return obj
except json.JSONDecodeError:
idx = text.find("{", idx)
if idx == -1:
break
idx += 1
raise ValueError(f"未找到可解析的 JSON,原文:{text!r}")
def _to_int(v, default=0):
if v is None or v == "":
return default
if isinstance(v, bool):
return default
try:
f = float(v)
if f.is_integer():
return int(f)
except (TypeError, ValueError):
pass
warnings.warn(f"age 字段无法转成整数,已默认 {default}:{v!r}")
return default
def parse_person(raw: str) -> dict:
data = _extract_json(raw)
if not isinstance(data, dict):
raise TypeError("JSON 顶层必须是对象")
name = data.get("name", "")
name = "" if name is None else str(name).strip()
age = _to_int(data.get("age"), 0)
skills = data.get("skills", [])
if skills is None:
skills = []
if isinstance(skills, str):
skills = [s.strip() for s in skills.split(",") if s.strip()]
elif isinstance(skills, list):
cleaned = []
for s in skills:
if isinstance(s, str):
cleaned.append(s.strip())
elif isinstance(s, (int, float)):
cleaned.append(str(s))
else:
warnings.warn(f"skills 里跳过非字符串项:{s!r}")
skills = cleaned
else:
warnings.warn(f"skills 字段类型异常,已默认 []:{skills!r}")
skills = []
return {"name": name, "age": age, "skills": skills}
def extract_person_from_text(text: str, client=None):
client = client or OpenAI()
resp = client.chat.completions.create(
model="gpt-4o-mini", # 想更稳可以换成 gpt-4o
response_format={"type": "json_object"},
messages=[
{
"role": "user",
"content": PROMPT_TEMPLATE.replace("{{text}}", text),
}
],
temperature=0,
)
raw = resp.choices[0].message.content
retur
点左边「开工 · 直接出成品」,出一份你自己的版本(文字免费)