Connect evidence-backed business model assessments to company categories

This commit is contained in:
2026-11-01 00:00:35 +08:00
parent c833aa56c1
commit 5b31fa5b77
7 changed files with 113 additions and 7 deletions
@@ -2,6 +2,7 @@ import { useEffect, useMemo, useRef, useState } from "react";
import { useRouter } from "next/router";
import IncomeDistribution from "./IncomeDistribution";
import ArrDisclosures from "./ArrDisclosures";
import BusinessModelAssessment from "./BusinessModelAssessment";
import {
categorySummary, evidenceUrl, technicalReviewLabels, reviewCompanyIds, type ResearchEvidence, type ResearchReview, type ResearchSnapshot,
} from "@/lib/ai-research";
@@ -56,7 +57,7 @@ export default function AICompanyResearch() {
: router.isReady && typeof linkedCompany === "string" && data?.companies.some((c) => c.id === linkedCompany)
? linkedCompany : null;
function setSelected(id: string | null) { setSelection({ route: router.asPath, id }); }
const [tab, setTab] = useState<"companies" | "revenue" | "sources" | "reviews">("companies");
const [tab, setTab] = useState<"companies" | "revenue" | "models" | "sources" | "reviews">("companies");
const companySection = useRef<HTMLElement>(null);
const detailSection = useRef<HTMLElement>(null);
useEffect(() => {
@@ -128,7 +129,7 @@ export default function AICompanyResearch() {
<section ref={companySection} className="research-section" aria-labelledby="research-records-title">
<h2 id="research-records-title">研究数据</h2>
<div className="research-tabs" role="group" aria-label="研究数据视图">
{([['companies','公司与产品'],['revenue','收入观测'],['sources','原始证据'],['reviews','核查记录']] as const).map(([id,label]) =>
{([['companies','公司与产品'],['revenue','收入观测'],['models','商业模式初评'],['sources','原始证据'],['reviews','核查记录']] as const).map(([id,label]) =>
<button key={id} aria-pressed={tab === id} onClick={() => setTab(id)}>{label}</button>)}
</div>
{tab === "companies" && <>
@@ -153,6 +154,7 @@ export default function AICompanyResearch() {
{!filtered.length && <p className="research-message">没有匹配公司,请调整筛选条件。</p>}
{filtered.length > pageSize && <nav className="research-pagination" aria-label="公司数据分页"><button disabled={page === 0} onClick={() => setPage((n) => n - 1)}>上一页</button><span>{page + 1} / {Math.ceil(filtered.length / pageSize)}</span><button disabled={(page + 1) * pageSize >= filtered.length} onClick={() => setPage((n) => n + 1)}>下一页</button></nav>}
</>}
{tab === "models" && <BusinessModelAssessment data={data} onSelect={setSelected} onChooseCategory={chooseCategory} />}
{tab === "revenue" && <>
<IncomeDistribution data={data} onSelect={setSelected} />
<ArrDisclosures data={data} onSelect={setSelected} />
@@ -0,0 +1,32 @@
import { businessModelReviewType, evidenceUrl, reviewCompanyIds, type ResearchSnapshot } from "@/lib/ai-research";
export default function BusinessModelAssessment({ data, onSelect, onChooseCategory }: {
data: ResearchSnapshot; onSelect: (id: string) => void; onChooseCategory: (id: string) => void;
}) {
const reviews = data.reviews.filter((review) => review.type === businessModelReviewType && review.scope === "companies");
const evidence = new Map(data.evidence.map((item) => [item.id, item]));
return <section aria-labelledby="research-models-title">
<h3 id="research-models-title">商业模式初评</h3>
<p>从已核个案提炼收费方式、成本约束与下一步验证条件。已知事实与研究判断分列;同一种收费方式可以跨业务分类,以下个案不能代表整个行业。</p>
<p className="research-muted">这是基于当前证据的初步评估,不是收入预测或盈利排名。判断能否用于我们的业务,还需用实际客户任务、付费留存与交付成本验证;ARR 或平台 MRR 单独不能证明利润。</p>
{reviews.length ? <div className="research-table-wrap"><table>
<caption>收费模式与业务分类、公司明细及原始证据相互关联</caption>
<thead><tr><th scope="col">模式 / 业务分类</th><th scope="col">已核事实</th><th scope="col">初步判断 / 验证条件</th><th scope="col">参考个案与证据</th></tr></thead>
<tbody>{reviews.map((review) => {
const companyIds = new Set(reviewCompanyIds(data, review));
const companies = data.companies.filter((company) => companyIds.has(company.id));
const categories = data.categories.filter((category) => companies.some((company) => company.cat === category.id));
return <tr key={review.id}>
<td><strong>{review.company}</strong><div>{categories.map((category) => <button key={category.id} onClick={() => onChooseCategory(category.id)}>{category.name}</button>)}</div></td>
<td>{review.summary}</td><td>{review.handling}</td>
<td><div>{companies.map((company) => <button key={company.id} className="research-company-name" onClick={() => onSelect(company.id)}>{company.name}</button>)}</div>
<div>{review.evidenceIds.map((id) => {
const item = evidence.get(id); const url = item && evidenceUrl(item.url);
return item && url ? <p key={id}><a href={url} target="_blank" rel="noopener noreferrer">{item.title} ↗</a></p> : null;
})}</div>
</td>
</tr>;
})}</tbody>
</table></div> : <p>当前数据版本尚未记录商业模式初评。</p>}
</section>;
}
+1
View File
@@ -1,4 +1,5 @@
export type ResearchCategory = { id: string; name: string; description: string };
export const businessModelReviewType = "商业模式初评";
export const technicalReviewLabels = {
unreviewed: "技术证据尚未专项评审",
description: "已读技术自述",
+7 -2
View File
@@ -8,7 +8,7 @@ import coverageAudit from "../../../content/research/ai-companies.coverage.json"
import incomeReference from "../../../content/research/ai-income-analysis.json";
import { readResearchSnapshot } from "../src/lib/ai-research-store";
import { openSiteDatabase } from "../src/lib/site-database";
import { categorySummary, evidenceUrl, reviewCompanyIds, validateResearch, type ResearchSnapshot } from "../src/lib/ai-research";
import { businessModelReviewType, categorySummary, evidenceUrl, reviewCompanyIds, validateResearch, type ResearchSnapshot } from "../src/lib/ai-research";
import { consumeCode, initializeStore } from "../src/lib/auth-store";
import { newAuthConfig } from "../src/lib/auth";
import { arrDisclosureCoverage, arrDisclosures, arrFieldGaps, compareIncomeGroups, describeIncome, groupIncome, platformIncomeSample } from "../src/lib/research-statistics";
@@ -126,6 +126,11 @@ test("research revisions share the authentication database and preserve replay l
assert.equal(initial.companies.length, 1199);
assert.equal(initial.evidence.length, 4667);
assert.equal(initial.observations.length, 453);
const businessReviews = initial.reviews.filter((review) => review.type === businessModelReviewType);
assert.equal(businessReviews.length, 4);
assert.deepEqual(businessReviews, seed.reviews.filter((review) => review.type === businessModelReviewType)
.sort((a, b) => a.id.localeCompare(b.id)),
"business model assessments and company/evidence links persist in the shared database");
assert.deepEqual(initial.candidateBatches, seed.candidateBatches, "candidate gaps persist in the same database metadata");
assert.deepEqual(initial.directoryRechecks, seed.directoryRechecks, "follow-up classifications persist without rewriting the discovery audit");
assert.deepEqual(readResearchSnapshot(), initial, "reopening does not duplicate records");
@@ -164,7 +169,7 @@ test("research validation rejects broken evidence and unsafe source links", () =
test("reviews link explicit companies without turning global or excluded cases into companies", () => {
const snapshot = structuredClone(seed) as ResearchSnapshot;
assert.equal(snapshot.reviews.filter((r) => r.scope === "companies").length, 210);
assert.equal(snapshot.reviews.filter((r) => r.scope === "companies").length, 214);
assert.equal(snapshot.reviews.filter((r) => r.scope === "dataset").length, 143);
assert.equal(snapshot.reviews.filter((r) => r.scope === "excluded-candidate").length, 46);
const review = snapshot.reviews.find((r) => r.id === "R4")!;
+67 -1
View File
@@ -1,5 +1,5 @@
{
"version": "2026-10-31-duix-ez-entity-1",
"version": "2026-10-31-business-models-1",
"asOf": "2026-10-31",
"scope": "全球公开资料研究:保留首批个案,并扩展核查2025—2026八个YC批次候选池;成立年份以官方公司页面字段为依据。",
"limitations": [
@@ -104997,6 +104997,72 @@
"ENTITY2-EZ-PRIVACY"
],
"handling": "保持候选待核,不把共同创始人/产品更名代法律沿革。MRR增长无金额/截至日不作财务观测,终身/赠送不年化ARR;7/30日退款可能方案/版本不同,待核不判造假,旧NewOaks收入不转移。"
},
{
"id": "MODEL1-APP-CREDITS",
"type": "商业模式初评",
"company": "应用订阅+消耗额度",
"companyIds": [
"AI056",
"AI105",
"AI107"
],
"scope": "companies",
"summary": "已核事实:Base44以消息/集成额度分档,StoreClaw有订阅及充值,ChartGen另有日票/免费和购买积分。价表说明收费设计,未证明这些公司的付费留存或单位交付利润;免费/赠送与订阅收入分开。",
"evidenceIds": [
"ARRCHECK2-BASE-PRICE",
"PHALL26-STORE-PRICE",
"ADA1-BILLING"
],
"handling": "待验证判断:若客户持续重复同类任务,基础订阅可覆盖持续服务,消耗额度可约束重度使用成本。我们的试验应逐任务记录退款后实收、模型/工具/托管/人工支持成本、失败重试和30/90日付费留存;同时比较少量高消耗账户。只有净贡献与留存同时支持才扩大,不能用注册用户乘标价推ARR;年付现金、积分充值与当期收入需分。"
},
{
"id": "MODEL1-MARKETING",
"type": "商业模式初评",
"company": "面向营销团队的持续监测订阅",
"companyIds": [
"AI055"
],
"scope": "companies",
"summary": "已核事实:Peec按提示词、模型和项目分档,席位不限,提供不同API权限及Agent额度;公司发布客户和ARR声明,但客户总数未证全部付费,两个下界不能推出精确单客收入。",
"evidenceIds": [
"PEEC-PRICE",
"ARRCHECK2-PEEC-API",
"SACRA1-PEEC-ORIGINAL"
],
"handling": "待验证判断:若客户在每个周期都要监测并据结果采取行动,持续工作流可能支持续费。我们的验证应比较无工具时的基线、客户实际行动/复用频率、付费续费及扩张、数据采集和人工解释成本;区分品牌直客与代理分销。不把可见度提升自动归因于销售收入,也不据一个增长案例认定整个营销领域更优。"
},
{
"id": "MODEL1-GATEWAY",
"type": "商业模式初评",
"company": "模型网关:用量、平台费与订阅并存",
"companyIds": [
"MR017"
],
"scope": "companies",
"summary": "已核事实:LLM Gateway的API有用量和平台费、BYOK及企业安排,另有DevPass/Lounge订阅。现价不是历史收入拆分证据;平台MRR为历史快照且连接过期,不能当当前纯SaaS净收入。",
"evidenceIds": [
"MR2-LLM-PRICE",
"MR2-LLM-TERMS",
"MR2-LLM-WEB"
],
"handling": "待验证判断:若客户愿为路由、治理或可靠性支付独立服务费,才可能有区别于模型成本转售的价值。我们的验证需把充值、供应商成本、实际使用、平台净费和订阅分账,测量每付费项目的留存/净贡献、故障及支持成本;只按合同可持续服务部分评价经常性。一个平台产品不能代表基础设施行业均值。"
},
{
"id": "MODEL1-WORLD-API",
"type": "商业模式初评",
"company": "自研模型:研究产物到商业API",
"companyIds": [
"AI106"
],
"scope": "companies",
"summary": "已核事实:General Intuition有MIRA公开代码,官网称少量合作方接入商业API,未取得价格/付费合同。营销网站条款与Medal旧服务分离,融资及旧平台数据/用户不作新公司收入,代码未独立运行。",
"evidenceIds": [
"SACRA1-GI-HOME",
"SACRA1-GI-CODE",
"SACRA1-GI-TERMS"
],
"handling": "待验证判断:只有客户任务的独立质量收益能覆盖训练、数据许可、推理和支持成本,自研模型才构成可评估的商业路线。我们的下一步应先建立任务基线和可重复评估,再核付费试点的预算/采购周期、数据权利、训练摊销和单位推理成本;技术代码、合作标志与融资都不能代付费需求。当前证据不足以比较此路线与订阅应用的财务回报。"
}
],
"coverage": {
+1 -1
View File
@@ -1,5 +1,5 @@
{
"version": "2026-10-31-duix-ez-entity-1",
"version": "2026-10-31-business-models-1",
"scopeConfirmedAt": "2026-10-30",
"acceptance": "以确认的公开来源清单为边界,逐条核对并标明缺项。",
"provenance": "S01—S12恢复自已提交用户的《AI公司研究_来源与分类模板》来源清单;S13—S16单列后续已使用的补充证据渠道,不将使用次数当作全量覆盖。",
+1 -1
View File
@@ -1,5 +1,5 @@
{
"sourceVersion": "2026-10-31-duix-ez-entity-1",
"sourceVersion": "2026-10-31-business-models-1",
"asOf": "2026-10-31",
"metric": "platform-mrr-usd",
"sampleUnit": "product-or-business",