最新资讯
dev.to 银行 77 意图分类最便宜 LLM:GPT-6.1 Terra 每次成功任务 $0.000727 theinformation.com Chesky的副业:Airbnb向CEO新设AI实验室出售IP theverge.com OpenAI 宣布数据中心项目不再与公职人员签署保密协议 dev.to NVIDIA 发布四个开放 Cosmos 3 仿真模型 dev.to 真实 MCP 客户端击穿我们服务器的五种方式 theverge.com Airbnb 正在开发 AI 旅行 agent,计划 2027 年上半年推出 wechat 这可能是美国AI最魔幻的一天。 nytimes.com 美众议院共和党领袖要求 Nvidia 黄仁勋闭门简报 pub.towardsai.net 忘掉我:为记忆而设计的系统中的删除难题 marktechpost.com Google 发布 Gemini Omni 1.2 Flash:15 秒视频,每秒 0.07 美元 unite.ai Airbnb 计划推出覆盖规划、预订与客服的 AI 旅行 agent techcrunch.com Airbnb 称将于 2027 年上半年推出 AI 旅行代理
多元动态
登录 注册
大模型 dev.to · @Ahsan Ahmad

有据生成:让 LLM 基于真实数据起草项目章程而不产生幻觉

原文 我的收藏

作者介绍如何在 Django 中构建一个项目章程生成器:把 LLM 接入用户真实项目数据,生成范围说明、目标、理由等散文内容,同时拒绝编造不存在的目标、成功标准和干系人。文章区分了确定性的字段自动填充与基于真实数据的文本合成,强调在受治理的项目管理工具中,自信的虚构比空白字段更危险。采用自带 API key、不依赖框架魔法的方式实现。

AI推荐理由 这是一篇开发者实践记录,核心价值在于提出并演示一种“有据生成”思路:把 LLM 接到项目真实数据上生成项目章程,并明确拒绝编造不存在的目标、成功标准和干系人。文中给出了具体技术栈(Django、自带 API key、不用框架魔法),并区分了“确定性自动填充字段”与“基于真实数据合成散文”两种做法,对做 AI 应用落地、尤其是受治理的企业工具场景有参考意义。局限是正文片段只到方法介绍,未给出完整实现、评测数据或效果验证,属于经验分享而非可复现的基准结果。

62

正文

"Add AI" is the easiest line item on any 2026 roadmap and the easiest way to ship something worse than nothing. Wire an LLM to a "Generate charter" button, feed it the project name, and it will happily produce a beautifully-worded project charter full of objectives, success criteria and stakeholders that do not exist. In a governed project-management tool, a confident invention is worse than a blank field — someone might believe it. I wanted the generate button anyway, because there's a real version of it. Here's how I built a charter generator that drafts genuinely useful prose from the user's actual data, and refuses to make things up — in Django, bring-your-own-key, no framework magic. Two things this is not Not autopopulate. I already had a deterministic autopopulate: copy the sponsor from the project record, the dates from the schedule, and so on. That's great for fields, but a charter is mostly prose — a scope statement, an objectives section, a rationale — synthesised from the pre-project inputs (the business case, the benefits plan, the agreements). You can't str() your way to a scope statement. Autopopulate structurally can't do it. Not a free-form LLM. The other extreme — "here's the project name, write me a charter" — is exactly the hallucination machine. The model has no idea what your business case says, so it invents a plausible one. The useful thing lives in between: grounded synthesis. Read the real input documents, and ask the model to compose — using only what's actually there. Step 1: ground in the real inputs, not the model's imagination The whole trick is that the model's only source of truth is text you supply from the user's own documents — never its training data. In VanillaPM every document type declares its input documents (its ITTO prerequisites — the things that must exist before it). A charter's inputs are the business case, the benefits management plan, the agreements. So "grounding" is concrete: go read those documents. DOC_CHAR_CAP = 8_000 # per input document TOTAL_CONTEXT_CAP = 40_000 # the whole grounding context def input_documents(project, doc_type): """(type, title, text) for each declared prerequisite that exists and has readable text — each capped so one long doc can't dominate the context.""" out = [] for prereq in prerequisite_types(project, doc_type): # from the dependency graph doc = latest_of_type(project, prereq) text = document_text(doc) # walk the stored rich-text → plain text if text: out.append((prereq, doc.title, text[:DOC_CHAR_CAP])) return out Enter fullscreen mode Exit fullscreen mode Two boring-but-important details: Cap per document and in total. One 200-page attachment shouldn't crowd out the other inputs (or blow your context window / bill). A per-doc cap plus a total cap keeps the grounding balanced and bounded. Ground in authored text, not the whole DB. document_text() walks the document's stored rich-text tree and pulls the prose the human actually wrote — not a JSON dump of every model. The grounding context is then just: the deterministic structured facts (reused from autopopulate) + these input-document excerpts, under a big honest header. Step 2: the system prompt does the anti-hallucination work This is the part people skip. The model will fabricate unless you make refusing the easier path. Three rules, and the second one is the whole ballgame: SYSTEM_PROMPT = ( "You draft sections of a PMBOK-aligned project document.\n" "1. Ground every section ONLY in the provided project data and input " " documents below. They are your only source of truth.\n" "2. If the data a section needs is missing, write ONE short professional " " sentence stating what input is still needed — do NOT fabricate.\n" "3. Return JSON only: " '{"sections":[{"key":"","body":""}]}. ' "Use only the section keys given. No markdown headings, no preamble." ) Enter fullscreen mode Exit fullscreen mode Rule 2 is the difference between a demo and a tool. Giving the model an acceptable way to say "I don't have this" — a short "needs input: the benefits plan doesn't state a target ROI" placeholder — means it takes that exit instead of inventing a number. You're not just asking it not to hallucinate; you're handing it a better move than hallucinating. The user turn wires the sections to draft onto the grounding context: USER_PROMPT = ( "Draft these sections of the project's {doc_label}. Use each key exactly:\n\n" "{targets}\n\n" "=== PROJECT DATA AND INPUT DOCUMENTS (your only source of truth) ===\n" "{context}" ) Enter fullscreen mode Exit fullscreen mode Structured JSON out, fixed keys in. The model returns {"sections":[{"key", "body"}]} and may only use keys I gave it. That does two jobs: parsing is trivial and deterministic, and the model can't wander off and invent a "Section 12: Executive Bonus Plan." It fills the blanks I asked for, or it says it can't. Step 3: only touch the blanks, never the real data A charter is a mix of authored prose sections and live-data sections (a stakeholder table, a risk snapshot) that are generated from real records. The AI must never touch the latter — those aren't opinions to draft, they're facts to render. def target_sections(content_json, overwrite=False): for node in content_json.get("content", []): if section_has_datablock(node): # a live register/table snapshot continue # generated from real data — hands off if section_has_text(node) and not overwrite: continue # non-destructive: only fill empty sections yield node["attrs"]["key"], node["attrs"]["title"] Enter fullscreen mode Exit fullscreen mode So the fill is non-destructive (it never overwrites what a human wrote unless they ask) and it skips live-data sections entirely. The model works on empty prose sections and nothing else. Bonus: because the section keys/titles come from the document itself, the exact same code drafts a communications plan or a risk-management plan — it generalised for free. And the output lands in draft, for a human to review and approve. The AI proposes; the PM decides. It's never a fact until a person signs off. Step 4: bring-your-own-key, and fail safe No forced AI markup, and no crash when AI isn't configured. The path resolves BYOK-first: def resolve_ai_path(user, org): if byok_available(user, org): # user's own key return "byok", user_key(user), MODEL_BYOK # → free through us if managed_available(user, org): # metered credits return "managed", server_key(), MODEL_MANAGED return None, None, None # feature cleanly disabled Enter fullscreen mode Exit fullscreen mode And the SDK import is guarded — a server without the anthropic package (or a user without a key) degrades to a disabled button, never an exception: try: import anthropic _AVAILABLE = True except ImportError: anthropic, _AVAILABLE = None, False Enter fullscreen mode Exit fullscreen mode Nothing in the module holds a key; the caller passes the user's decrypted key in per request. (Load tests swap in an offline stub so they never hit the real API — cost and rate limits stay off the test path.) What grounding buys you — and what it doesn't Grounding isn't a hallucination cure; it's a hallucination budget. What it reliably buys: The model composes from your business case, so the objectives are your objectives. Missing inputs surface as honest "needs input" notes — which doubles as a checklist of what to go write. Structured, key-scoped output means no invented sections and trivial parsing. Non-destructive, draft-only, human-approved: the AI can't silently rewrite a governed document. What it doesn't do: it won't fix a vague business case (garbage in, grounded-garbage out), and a determined model can still mis-synthesise. So it's a draft generator with a human gate, not an autopilot — which is exactly what a governed document deserves. The pattern generalises well beyond charters: read the real inputs, cap and label them as the only source of truth, give the model an honest "I don't know," constrain the output shape, and never let it touch data it should only render. That's most of the distance between "we added AI" and AI you can actually put near real work. I'm building a free, full-lifecycle PM platform in the open — this generator ships in it (BYOK). If the build-in-public engineering is your thing, the rest of the series is here.

来源报道 · 1 篇 · 以下链接均前往原始媒体

← 返回精选动态 原文

更多内容