Level 3 — ProductionAlignment, Prompting & RAG

Alignment, Prompting & RAG

45 minutes60 marksprintable — key stays hidden on paper

Level 3 (Production): Derivations, Code-from-Memory & Explain-Out-Loud

Time limit: 45 minutes Total marks: 60

Answer all questions. Show all derivation steps. Code may be pseudo-Python but must be runnable-quality.


Q1. Derive the DPO objective from the RLHF/Bradley-Terry setup. (12 marks)

Starting from the KL-regularized RLHF objective maxπθ Ex,yπθ[r(x,y)]βKL ⁣(πθ(x)πref(x))\max_{\pi_\theta}\ \mathbb{E}_{x,y\sim\pi_\theta}[r(x,y)] - \beta\,\mathrm{KL}\!\left(\pi_\theta(\cdot|x)\,\|\,\pi_{\mathrm{ref}}(\cdot|x)\right)

(a) Show that the optimal policy has the closed form π(yx)=1Z(x)πref(yx)exp(r(x,y)/β)\pi^*(y|x)=\frac{1}{Z(x)}\pi_{\mathrm{ref}}(y|x)\exp(r(x,y)/\beta). (4) (b) Invert this to express the reward r(x,y)r(x,y) in terms of π\pi^*, πref\pi_{\mathrm{ref}} and Z(x)Z(x). (2) (c) Substitute into the Bradley-Terry preference model P(ywyl)=σ(r(x,yw)r(x,yl))P(y_w\succ y_l)=\sigma(r(x,y_w)-r(x,y_l)) and show the partition function Z(x)Z(x) cancels. (3) (d) Write the final DPO loss over a dataset D\mathcal{D} of (x,yw,yl)(x,y_w,y_l) triples. (3)


Q2. PPO clipped surrogate — explain out loud + compute. (10 marks)

(a) Write the PPO clipped surrogate objective with probability ratio rt(θ)r_t(\theta) and advantage AtA_t, and explain in 2–3 sentences why the clip prevents destructive updates. (5) (b) Given rt=1.4r_t=1.4, At=+2A_t=+2, ϵ=0.2\epsilon=0.2: compute the per-token surrogate value min(rtAt, clip(rt,1ϵ,1+ϵ)At)\min(r_tA_t,\ \mathrm{clip}(r_t,1-\epsilon,1+\epsilon)A_t). (2) (c) Repeat for rt=0.5r_t=0.5, At=3A_t=-3, ϵ=0.2\epsilon=0.2. State in one line whether the gradient contributes for each case. (3)


Q3. Reward model loss — from memory. (8 marks)

(a) Write the pairwise ranking loss used to train a reward model rϕr_\phi from human preference pairs (yw,yl)(y_w,y_l). (3) (b) A batch has three pairs with reward-margins (rwrl)(r_w-r_l) equal to 2.02.0, 0.00.0, and 1.0-1.0. Compute the mean loss (use natural log). (3) (c) Explain why reward models are typically initialized from the SFT model and use a scalar head. (2)


Q4. Self-consistency vs single-sample CoT — derive the win. (10 marks)

Suppose a model produces the correct final answer on any single chain-of-thought sample with probability p=0.55p=0.55, and wrong answers are spread so no single wrong answer beats the correct one under majority vote.

(a) For N=5N=5 independent samples, write the probability that the majority vote is correct (majority = at least 3 correct). (4) (b) Compute this probability numerically. (3) (c) Explain the assumption that most fails, in practice, that can make self-consistency underperform this idealized number. (3)


Q5. Build a minimal RAG pipeline from memory. (12 marks)

Write clean pseudo-Python for a RAG query function that: (a) embeds the query, (b) does cosine-similarity retrieval of top-kk chunks from a vector store, (c) reranks with a hybrid score s=αsdense+(1α)sbm25s = \alpha\cdot s_{\text{dense}} + (1-\alpha)\cdot s_{\text{bm25}}, (d) builds a grounded prompt, (e) calls the LLM. (8) Then in 4 bullet points explain two chunking strategy trade-offs and two hallucination-mitigation techniques your pipeline enables. (4)


Q6. Cosine similarity & normalization. (8 marks)

Given query embedding q=[1,2,2]q=[1,2,2] and two chunk embeddings c1=[2,0,1]c_1=[2,0,1], c2=[0,3,4]c_2=[0,3,4]. (a) Compute cosine similarity of qq with each and state which is retrieved as top-1. (5) (b) If embeddings are L2-normalized at index time, explain why inner-product search then equals cosine search, and why this speeds up ANN retrieval. (3)


Answer keyMark scheme & solutions

Q1 — DPO Derivation (12)

(a) (4) Rewrite objective per-prompt as minimizing Eyπ[logπ(yx)πref(yx)1βr(x,y)].\mathbb{E}_{y\sim\pi}\Big[\log\frac{\pi(y|x)}{\pi_{\mathrm{ref}}(y|x)} - \tfrac{1}{\beta}r(x,y)\Big]. This equals KL(π1Zπrefer/β)logZ(x)\mathrm{KL}\big(\pi \,\|\, \tfrac{1}{Z}\pi_{\mathrm{ref}}e^{r/\beta}\big) - \log Z(x) with Z(x)=yπref(yx)er(x,y)/βZ(x)=\sum_y \pi_{\mathrm{ref}}(y|x)e^{r(x,y)/\beta}. (2 marks) KL is minimized (=0) when π=π\pi=\pi^*, giving π(yx)=1Z(x)πref(yx)er(x,y)/β.\pi^*(y|x)=\tfrac{1}{Z(x)}\pi_{\mathrm{ref}}(y|x)e^{r(x,y)/\beta}. (2 marks)

(b) (2) Take logs and rearrange: r(x,y)=βlogπ(yx)πref(yx)+βlogZ(x).r(x,y)=\beta\log\frac{\pi^*(y|x)}{\pi_{\mathrm{ref}}(y|x)}+\beta\log Z(x).

(c) (3) In BT, only the difference matters: r(x,yw)r(x,yl)=βlogπ(ywx)πref(ywx)βlogπ(ylx)πref(ylx).r(x,y_w)-r(x,y_l)=\beta\log\frac{\pi^*(y_w|x)}{\pi_{\mathrm{ref}}(y_w|x)}-\beta\log\frac{\pi^*(y_l|x)}{\pi_{\mathrm{ref}}(y_l|x)}. The βlogZ(x)\beta\log Z(x) term is identical in both and cancels (1 mark for identifying cancellation; 2 for correct difference).

(d) (3) Replacing π\pi^* with the trainable πθ\pi_\theta: LDPO=E(x,yw,yl)D[logσ(βlogπθ(ywx)πref(ywx)βlogπθ(ylx)πref(ylx))].\mathcal{L}_{\text{DPO}}=-\mathbb{E}_{(x,y_w,y_l)\sim\mathcal{D}}\Big[\log\sigma\Big(\beta\log\tfrac{\pi_\theta(y_w|x)}{\pi_{\mathrm{ref}}(y_w|x)}-\beta\log\tfrac{\pi_\theta(y_l|x)}{\pi_{\mathrm{ref}}(y_l|x)}\Big)\Big].


Q2 — PPO Clip (10)

(a) (5) LCLIP(θ)=Et[min(rtAt, clip(rt,1ϵ,1+ϵ)At)]L^{\text{CLIP}}(\theta)=\mathbb{E}_t\big[\min(r_t A_t,\ \mathrm{clip}(r_t,1-\epsilon,1+\epsilon)A_t)\big], where rt=πθ(atst)πold(atst)r_t=\frac{\pi_\theta(a_t|s_t)}{\pi_{\text{old}}(a_t|s_t)}. (3) Why: the clip caps how far the new policy can move from the old one in a single update; taking the min makes the bound pessimistic so the objective never rewards moving outside the trust region — preventing large, destabilizing policy jumps. (2)

(b) (2) rtAt=1.4×2=2.8r_tA_t=1.4\times2=2.8; clipped ratio =1.2=1.2, 1.2×2=2.41.2\times2=2.4; min(2.8,2.4)=2.4\min(2.8,2.4)=\mathbf{2.4}.

(c) (3) rtAt=0.5×(3)=1.5r_tA_t=0.5\times(-3)=-1.5; clipped ratio =max(0.5,0.8)=0.8=\max(0.5,0.8)=0.8, 0.8×(3)=2.40.8\times(-3)=-2.4; min(1.5,2.4)=2.4\min(-1.5,-2.4)=\mathbf{-2.4}. (2) Case (b): clip is active, ratio was above 1+ϵ1+\epsilon with positive AA ⇒ gradient zero (no further push). Case (c): the 2.4-2.4 (unclipped, larger magnitude) is selected ⇒ gradient nonzero, pushing probability down. (1)


Q3 — Reward Model (8)

(a) (3) L(ϕ)=E(yw,yl)[logσ(rϕ(x,yw)rϕ(x,yl))].\mathcal{L}(\phi)=-\mathbb{E}_{(y_w,y_l)}\big[\log\sigma\big(r_\phi(x,y_w)-r_\phi(x,y_l)\big)\big].

(b) (3) Loss per pair =logσ(m)=-\log\sigma(m):

  • m=2m=2: logσ(2)=log(0.8808)=0.1269-\log\sigma(2)=-\log(0.8808)=0.1269
  • m=0m=0: log(0.5)=0.6931-\log(0.5)=0.6931
  • m=1m=-1: logσ(1)=log(0.2689)=1.3133-\log\sigma(-1)=-\log(0.2689)=1.3133

Mean =(0.1269+0.6931+1.3133)/3=0.7111=(0.1269+0.6931+1.3133)/3=\mathbf{0.7111}.

(c) (2) Init from SFT: shares language understanding, so preference signal only needs to fit a ranking head — cheaper and more stable. Scalar head: BT model needs a single real-valued score per response to compute margins.


Q4 — Self-Consistency (10)

(a) (4) Majority correct =k=35(5k)pk(1p)5k=\sum_{k=3}^{5}\binom{5}{k}p^k(1-p)^{5-k}, p=0.55p=0.55.

(b) (3)

  • k=3k=3: 100.5530.452=100.1663750.2025=0.33690910\cdot0.55^3\cdot0.45^2=10\cdot0.166375\cdot0.2025=0.336909
  • k=4k=4: 50.5540.45=50.091506250.45=0.2058895\cdot0.55^4\cdot0.45=5\cdot0.09150625\cdot0.45=0.205889
  • k=5k=5: 0.555=0.0503280.55^5=0.050328

Sum =0.5931=\mathbf{0.5931} (≈0.593), higher than single-sample 0.550.55. ✓

(c) (3) The assumption of independence of samples fails: chains sampled from the same model are correlated (shared biases/failure modes), and wrong answers can cluster on a single plausible-but-wrong value that beats the correct answer under majority vote — collapsing the gain or reversing it.


Q5 — RAG Pipeline (12)

(a) (8) Reference solution:

def rag_query(query, store, llm, embed, bm25, k=20, alpha=0.6):
    q_vec = embed(query)                              # (a) embed
    # (b) dense retrieval by cosine
    cand = store.search(q_vec, top_k=k, metric="cosine")
    # (c) hybrid rerank
    for c in cand:
        s_dense = cosine(q_vec, c.vec)
        s_bm25  = bm25.score(query, c.text)
        c.score = alpha*s_dense + (1-alpha)*normalize(s_bm25)
    top = sorted(cand, key=lambda c: c.score, reverse=True)[:5]
    # (d) grounded prompt
    ctx = "\n\n".join(f"[{i}] {c.text}" for i, c in enumerate(top))
    prompt = (f"Answer ONLY from context. Cite [i]. "
              f"If not present, say 'not in context'.\n\n"
              f"Context:\n{ctx}\n\nQ: {query}\nA:")
    return llm(prompt)                                # (e) call LLM

Marks: embed(1), retrieval(2), hybrid rerank(2), grounded/cited prompt(2), LLM call(1).

(b) (4) — 1 mark each:

  • Chunk size trade-off: large chunks preserve context but dilute embeddings & waste context window; small chunks are precise but fragment meaning across boundaries.
  • Overlap trade-off: sliding-window overlap avoids splitting an answer across chunks but inflates index size and causes duplicate retrievals.
  • Hallucination mitigation: grounding instruction + "say 'not in context'" abstention reduces fabrication.
  • Hallucination mitigation: inline citation [i] forces attribution, enabling faithfulness checks / self-verification.

Q6 — Cosine (8)

(a) (5) q=[1,2,2]q=[1,2,2], q=3\|q\|=3.

  • c1=[2,0,1]c_1=[2,0,1]: dot =2+0+2=4=2+0+2=4, c1=5\|c_1\|=\sqrt5, cos =4/(35)=0.5963=4/(3\sqrt5)=0.5963.
  • c2=[0,3,4]c_2=[0,3,4]: dot =0+6+8=14=0+6+8=14, c2=5\|c_2\|=5, cos =14/15=0.9333=14/15=0.9333.

Top-1 retrieved: c2c_2. (dot each 1, norms 1, values 2, decision 1)

(b) (3) After L2 normalization c=1\|c\|=1, so qc=qcqcq\cdot c=\frac{q\cdot c}{\|q\|\|c\|}·(const) — inner product equals cosine up to the fixed q\|q\| which is monotone-invariant for ranking. ANN indexes (IVF/HNSW) use raw inner-product/L2 distance kernels that are cheaper than dividing by norms per comparison, so pre-normalizing lets the fast IP search return exact cosine order.

[
{"claim":"Q2b clipped surrogate = 2.4","code":"rt=Rational(14,10);At=2;eps=Rational(2,10);val=Min(rt*At, Max(1-eps,Min(rt,1+eps))*At);result=(val==Rational(24,10))"},
{"claim":"Q2c clipped surrogate = -2.4","code":"rt=Rational(5,10);At=-3;eps=Rational(2,10);val=Min(rt*At, Max(1-eps,Min(rt,1+eps))*At);result=(val==Rational(-24,10))"},
{"claim":"Q3b mean reward-model loss approx 0.7111","code":"import sympy as sp;f=lambda m:-sp.log(1/(1+sp.exp(-m)));mean=(f(2)+f(0)+f(-1))/3;result=abs(float(mean)-0.7111)<1e-3"},
{"claim":"Q4b self-consistency prob approx 0.5931","code":"p=Rational(55,100);from sympy import binomial;s=sum(binomial(5,k)*p**k*(1-p)**(5-k) for k in range(3,6));result=abs(float(s)-0.5931)<1e-3"},
{"claim":"Q6a cosine c2 > c1 so c2 top1","code":"import sympy as sp;q=sp.Matrix([1,2,2]);c1=sp.Matrix([2,0,1]);c2=sp.Matrix([0,3,4]);cos1=q.dot(c1)/(q.norm()*c1.norm());cos2=q.dot(c2)/(q.norm()*c2.norm());result=(cos2>cos1)"}
]