定制 twdnhfr/laravel-bes-rag 二次开发

按需修改功能、优化性能、对接业务系统,提供一站式技术支持

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

twdnhfr/laravel-bes-rag

最新稳定版本:v0.2.1

Composer 安装命令:

composer require twdnhfr/laravel-bes-rag

包简介

A deep RAG search orchestrator for Laravel, based on Bidirectional Evolutionary Search (BES): backward goal decomposition, evolving evidence trails and cited, auditable answers.

README 文档

README

A deep RAG search orchestrator for Laravel, based on Bidirectional Evolutionary Search (BES): instead of question → top-k → answer, hard multi-hop questions are decomposed into checkable sub-goals, multiple evidence trails are evolved against them, and the final answer is synthesized strictly from cited evidence — with a full audit trail of every query, chunk and score.

Built on the Laravel AI SDK (laravel/ai) as the provider-agnostic engine for text generation, structured output and embeddings.

Question
  → backward decomposition: checkable sub-goals with declarative verifiers
  → forward search: seed multiple retrieval/answer trails
  → scoring: evidence coverage, groundedness, citation support, contradictions
  → evolution: expand / combine / delete / translocate / crossover
  → final answer: best grounded terminal trail, synthesized from its evidence only

When to use this: BES-RAG is a deep research mode for hard, multi-hop questions where plain top-k RAG fails. It costs a multiple of a single RAG call (budgeted and capped, but real). Don't route every query through it.

Installation

composer require twdnhfr/laravel-bes-rag

php artisan vendor:publish --tag="bes-rag-migrations"
php artisan migrate

php artisan vendor:publish --tag="bes-rag-config"   # optional

Quick start

The only contract you must provide is the Retriever — the adapter to your vector store or search index:

use Twdnhfr\BesRag\Contracts\Retriever;
use Twdnhfr\BesRag\Data\RetrievalQuery;
use Twdnhfr\BesRag\Data\RetrievedChunk;

class PgVectorRetriever implements Retriever
{
    public function retrieve(RetrievalQuery $query, int $topK = 5): array
    {
        // query your store, return RetrievedChunk[]
    }
}

Then run a deep search:

use Twdnhfr\BesRag\Facades\BesRag;

$result = BesRag::make()
    ->retriever(new PgVectorRetriever)
    ->budget(30)
    ->maxDepth(3)
    ->answer('Who founded the company that produces the Model S?');

$result->answer();         // cited answer: "... [doc_42/chunk_3]"
$result->citations();      // [['document_id' => 'doc_42', 'chunk_id' => 'chunk_3'], ...]
$result->evidenceTrail();  // the full winning trail for auditing
$result->scores();         // raw / backward / effective + per-goal coverage

Multi-tenant stores scope retrieval per run via ->retrievalContext([...]) — the array is persisted with the run (so queue workers see it) and arrives at your retriever as RetrievalQuery->filters:

BesRag::make()->retrievalContext(['brain_id' => $brain->id])->dispatch($question);

Async via queue pipeline

// Bind the retriever so queue workers can rebuild the engine:
$this->app->bind(\Twdnhfr\BesRag\Contracts\Retriever::class, PgVectorRetriever::class);

$result = BesRag::make()->dispatch($question);   // returns immediately
$result->id();                                   // poll later:
BesRag::result($id)->finished();

The pipeline runs StartRun → SeedCandidates → SearchStep (self-redispatching) → FinalizeAnswer. Payloads carry only the run id; all artifacts live in the database.

HTTP API (opt-in)

Set BES_RAG_ROUTES_ENABLED=true (add your own auth middleware via bes-rag.routes.middleware):

Method Route Purpose
POST /bes-rag/deep-answer start a run ({question, sync?, budget?})
GET /bes-rag/runs/{run} status + answer
GET /bes-rag/runs/{run}/debug goal tree, all candidates, scores, steps
GET /bes-rag/runs/{run}/stream SSE progress events

How it works

Backward decomposition

The question is decomposed (via LLM structured output) into atomic sub-goals with declarative verifiers — never LLM-generated code:

Verifier type Checks
semantic_query_coverage a trail query/chunk is semantically close to the goal (embeddings)
evidence_presence ≥ N evidence chunks with source metadata
citation_support answer claims are backed by cited chunks (LLM judge)
entity_match required entities/dates literally appear in evidence
contradiction_check no evidence strongly contradicts the answer (LLM judge)
dependency_satisfied gating on depends_on goals

Register your own via ->verifier('my_type', new MyVerifier).

Forward search & evolution

A candidate is an EvidenceTrail (queries → retrieved chunks → selected evidence → synthesis notes → answer draft), not just an answer. Parents are selected by Boltzmann sampling over effective scores (temperature annealed across the budget); pair operators pick complementary parents. Default operator mix (configurable):

expand 70% · combine 10% · translocate 7.5% · crossover 7.5% · delete 5%

crossover cuts along goal boundaries, never blindly by step index — source context stays intact.

Scoring

raw_score      = weighted(groundedness, citation support, evidence quality,
                          contradiction absence, source diversity)
backward_score = recursive goal-tree score (alpha-blend of self + children)
effective      = bucket_interpolation(raw, backward)   ← default

The bucket policy makes the hard signal dominate: a trail that merely "looks topically right" to the goal tree can never outrank a meaningfully better-grounded trail. Backward score only breaks ties within a raw-score bucket. (score_policy: weighted gives the simple linear blend.)

Cost control

Two independent caps stop a run deterministically: the step budget (budget) and the LLM call cap (max_llm_calls) — one search step can trigger several LLM calls, so the step budget alone doesn't bound cost. The LLM judge (groundedness/citations/contradictions) is one memoized structured call per scored trail. Embeddings are cached in-process and optionally in a Laravel cache store.

Thresholds are embedder-relative. thresholds.semantic_coverage: 0.72 is calibrated for MiniLM-class embeddings. Recalibrate against a small eval set when you switch embedding models.

Testing your integration

The package ships deterministic fakes (no HTTP):

use Twdnhfr\BesRag\Testing\FakeLlm;
use Twdnhfr\BesRag\Testing\FakeEmbedder;
use Twdnhfr\BesRag\Retrieval\ArrayRetriever;

$llm = (new FakeLlm)
    ->onStructured(fn ($instructions, $prompt) => [...])
    ->onText(fn () => 'Answer with citation [doc/c1].');

$result = BesRag::make()
    ->retriever(new ArrayRetriever([...chunks...]))
    ->llm($llm)
    ->embedder(new FakeEmbedder)
    ->answer('...');

Configuration

See config/bes-rag.php — provider/models per purpose (decompose/expand/verify/synthesize/embeddings), budgets, operator mix, scoring weights, thresholds, queue and routes. Everything is also overridable per run through the fluent builder.

What this deliberately does not do

  • No dynamic code eval. The original BES inference code verifies goals with Python eval; this package uses registered, declarative verifiers only.
  • No blind step concatenation. Evolution operators cut along goal boundaries to preserve source context.
  • No backward-score dominance. Groundedness and citation support always outrank topical coverage.

Credits & paper

Independent Laravel implementation of the search method from:

Xu, Qi, Su, Ye, Lakkaraju, Kakade, Du — Self-Improving Language Models with Bidirectional Evolutionary Search (arXiv:2605.28814, project page, code)

No shared code or affiliation; the multi-hop adaptation follows the paper's appendix.

License

MIT — see LICENSE.md.

统计信息

  • 总下载量: 0
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 0
  • 点击次数: 2
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 0
  • Watchers: 0
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2026-06-10

承接程序开发

PHP开发

VUE

Vue开发

前端开发

小程序开发

公众号开发

系统定制

数据库设计

云部署

网站建设

安全加固